Dictionaries & Sets
What is a Dictionary?
A dictionary stores data as key-value pairs. Instead of accessing items by numeric index like a list, you access them by a meaningful key — a label you define. This makes dicts perfect for representing real-world objects like users, products, or settings.
Dicts are mutable, ordered (Python 3.7+), and do not allow duplicate keys. Looking up a value by key is extremely fast — O(1) — regardless of how many items the dict contains.
# Creating a dictionary student = { "name" : "Fatima Malik", "age" : 20, "gpa" : 3.92, "active" : True } # Accessing values by key print(student["name"]) # Fatima Malik print(student["gpa"]) # 3.92 # .get() — safe access (no KeyError) print(student.get("age")) # 20 print(student.get("email")) # None (key missing) print(student.get("email", "N/A")) # N/A (default provided) # Add or update a key student["email"] = "fatima@bwb.com" # add new student["age"] = 21 # update existing # Delete a key del student["active"] removed = student.pop("gpa") # remove + return print(f"Removed GPA: {removed}") # Check if key exists print("name" in student) # True print("phone" in student) # False print(len(student)) # number of key-value pairs
Iterating Dictionaries
Three views let you loop over different aspects of a dictionary. Each returns a special view object that always reflects the current state of the dict.
| Method | Returns | Yields |
|---|---|---|
| .keys() | dict_keys | All keys — same as for k in d |
| .values() | dict_values | All values |
| .items() | dict_items | (key, value) tuples — most useful for loops |
| .update(d2) | None | Merge d2 into dict — overwrites duplicate keys |
| .setdefault(k, v) | value | Get value for k; if missing, insert k:v first |
| .copy() | dict | Shallow copy of the dictionary |
scores = {"Ali": 88, "Sara": 95, "Zara": 72} # Loop over keys for name in scores: print(name, end=" ") # Ali Sara Zara # Loop over values for score in scores.values(): print(score, end=" ") # 88 95 72 # Loop over key-value pairs — most common for name, score in scores.items(): grade = "A" if score >= 80 else "B" print(f" {name:8} {score} {grade}") # Merge two dicts extra = {"Omar": 80, "Sara": 98} # Sara's score updated scores.update(extra) print(scores) # {'Ali': 88, 'Sara': 98, 'Zara': 72, 'Omar': 80} # Dict comprehension doubled = {k: v * 2 for k, v in scores.items()} passing = {k: v for k, v in scores.items() if v >= 80} print(passing) # {'Ali': 88, 'Sara': 98, 'Omar': 80}
Nested Dicts & Real Patterns
Dictionaries are the building block of almost all Python data — JSON APIs, database records, configuration files, and objects are all represented as nested dicts in practice.
# ── Nested dict — user record ───────────────── user = { "id" : 1001, "name" : "Ali Hassan", "address" : { "city" : "Lahore", "country": "Pakistan" }, "courses" : ["Python", "Web Dev"] } print(user["address"]["city"]) # Lahore print(user["courses"][0]) # Python # ── Word frequency counter ──────────────────── text = "apple banana apple mango banana apple" freq = {} for word in text.split(): freq[word] = freq.get(word, 0) + 1 print(freq) # {'apple': 3, 'banana': 2, 'mango': 1} # ── Grouping items ──────────────────────────── students = [ {"name": "Ali", "grade": "A"}, {"name": "Sara", "grade": "B"}, {"name": "Zara", "grade": "A"}, ] by_grade = {} for s in students: g = s["grade"] by_grade.setdefault(g, []).append(s["name"]) print(by_grade) # {'A': ['Ali', 'Zara'], 'B': ['Sara']}
dict.get(key, 0) + 1 is the frequency counter pattern.get(word, 0) safely returns 0 if the word hasn't been seen yet, so you can safely add 1. This pattern shows up in interview questions, log analysers, text processors, and data science constantly.Sets — Unique Unordered Collections
A set is an unordered collection of unique items. Duplicate values are automatically discarded. Sets are incredibly fast for membership testing and are the go-to tool for deduplication and mathematical set operations.
Sets use { } but without key-value pairs. Creating an empty set requires set() — not {}, which creates an empty dict.
# Creating sets — duplicates auto-removed colours = {"red", "blue", "green", "red"} print(colours) # {'blue', 'green', 'red'} — order not guaranteed empty_set = set() # NOT {} (that's an empty dict!) # Set from a list — fast deduplication nums = [1, 2, 2, 3, 3, 3, 4] unique = set(nums) print(unique) # {1, 2, 3, 4} # Set operations python_students = {"Ali", "Sara", "Zara", "Omar"} webdev_students = {"Sara", "Bilal", "Zara"} print(python_students | webdev_students) # Union — all students print(python_students & webdev_students) # {'Sara', 'Zara'} — in both print(python_students - webdev_students) # {'Ali', 'Omar'} — Python only print(python_students ^ webdev_students) # {'Ali', 'Omar', 'Bilal'} — not shared # Membership test — O(1) speed print("Sara" in python_students) # True — instant lookup # Add and remove python_students.add("Nadia") python_students.discard("Omar") # safe — no error if missing # Subset / superset checks print({"Sara", "Zara"}.issubset(python_students)) # True
unique = list(set(my_list)) removes all duplicates instantly. The conversion to set discards duplicates, then converting back to list gives you a clean list. Note: this does NOT preserve order. If order matters, use list(dict.fromkeys(my_list)) instead (Python 3.7+).Choosing the Right Collection
Python's four main collection types each have a distinct purpose. Picking the right one for your data makes code cleaner, faster, and less error-prone.
# list — ordered, can change, can repeat cart = ["apple", "milk", "apple"] # duplicates fine # tuple — fixed record, hashable (can be dict key) coord = (33.6844, 73.0479) # Islamabad lat/lon locations = {coord: "Islamabad"} # tuple as dict key # dict — label your data config = {"debug": False, "port": 8000, "host": "0.0.0.0"} # set — fast membership, remove duplicates visited_pages = {"/home", "/about", "/home"} # only 2 stored if "/contact" not in visited_pages: print("First visit to /contact") # Practical: find students enrolled in ALL three courses python = {"Ali", "Sara", "Zara", "Omar"} webdev = {"Sara", "Zara", "Bilal"} data = {"Zara", "Sara", "Nadia"} all_three = python & webdev & data print(f"Enrolled in all 3: {all_three}") # {'Sara', 'Zara'}
d.get("email", "N/A") return when "email" is not in dict d?{1, 2, 3} & {2, 3, 4}?{} create in Python?{"a":1,"b":2,"c":3}["b"]?1. Stores contacts as a dict of dicts:
{"Ali": {"phone": "...", "email": "...", "tags": {...}}}2. Lets the user add, view, search, and delete contacts via a while-loop menu
3. Contact tags are stored as a set (e.g.
{"friend", "work"})4. Uses a dict comprehension to find all contacts tagged with a specific tag
5. Uses
.get() for safe lookups and in for existence checks6. On exit, shows a summary: total contacts and all unique tags (union of all tag sets)
💡 Show hints
- Structure:
contacts = {"Ali": {"phone": "...", "tags": {"friend"}}} - Add tags as set:
{"friend", "work"}— auto-deduplicates - Find by tag:
{n: c for n, c in contacts.items() if tag in c["tags"]} - All unique tags:
all_tags = set().union(*[c["tags"] for c in contacts.values()])
# ── Contact Book ────────────────────────────── contacts = {} def show_menu(): print("\n 1) Add contact 2) View contact") print(" 3) Search by tag 4) Delete contact") print(" 5) List all 6) Quit") while True: show_menu() choice = input(" Choose: ").strip() if choice == "1": name = input(" Name : ").strip().title() phone = input(" Phone : ").strip() email = input(" Email : ").strip().lower() tags = set(input(" Tags (comma-sep): ").split(",")) contacts[name] = {"phone": phone, "email": email, "tags": tags} print(f" ✅ {name} added.") elif choice == "2": name = input(" Name: ").strip().title() c = contacts.get(name) if c: print(f" 📞 {c['phone']} 📧 {c['email']} 🏷️ {', '.join(c['tags'])}") else: print(" ❌ Not found.") elif choice == "3": tag = input(" Tag: ").strip().lower() result = {n: c for n, c in contacts.items() if tag in c["tags"]} for n in result: print(f" → {n}") elif choice == "4": name = input(" Name: ").strip().title() contacts.pop(name, None) print(f" 🗑️ {name} deleted.") elif choice == "5": for n, c in contacts.items(): print(f" {n:15} {c['phone']}") elif choice == "6": all_tags = set().union(*[c["tags"] for c in contacts.values()]) if contacts else set() print(f"\n Contacts: {len(contacts)} | All tags: {', '.join(all_tags) or 'none'}") break