-
Section 1: Getting Started
-
Section 2: Core Syntax and Data Types
-
Section 3: Collections
-
39: Set Operations: Union, Intersection, Difference
-
Section 4: Control Flow
-
Section 5: Functions
-
Section 6: Turtle Graphics and Early Practice Projects
-
Section 7: Working with Files and I/O
-
Section 8: Regular Expressions
-
Section 9: Object-Oriented Python
-
Section 10: Error Handling
-
Section 11: Modules and Packages
-
Section 12: Iterators, Generators, and Functional Tools
-
Section 13: Decorators and Metaprogramming
-
Section 14: Concurrency and Parallelism
-
Section 15: Working with Dates, Times, and Numbers
-
Section 16: Standard Library Deep Dive I: Data Structures
-
Section 17: Standard Library Deep Dive II: System and Introspection
-
Section 18: Standard Library Deep Dive III: Security and Encoding
-
Section 19: Standard Library Deep Dive IV: Text and Data Utilities
-
Section 20: Networking and Web Basics
-
Section 21: Working with Databases
-
Section 22: Testing and Quality
-
Section 23: Advanced Typing
-
Section 24: Context Managers and Resource Handling
-
Section 25: Text, Unicode, and Binary Data
-
Section 26: More Functional and Iteration Tools
-
Section 27: Data Validation and Configuration
-
Section 28: Working with Images and Media
-
Section 29: Property-Based and Documentation Testing
-
Section 30: Packaging and Deployment
-
Section 31: Performance and Internals
-
Section 32: Design Patterns in Python
-
Section 33: GUI Programming
-
Section 34: Security Basics
-
Section 35: Data Structures and Algorithms
-
Section 36: Practical Projects
-
Section 37: Capstone Projects
-
Section 38: Interview and Algorithm Practice
-
Section 39: Writing Idiomatic Python
46: Practice Exercise: Building a Contact Book with Dictionaries
A few years ago, I was reviewing code for a junior developer who was building a simple internal directory. He had decided to store the employee names in one list and their phone numbers in another list, keeping them "synchronized" by index. It worked fine until he tried to implement a sorting feature. He sorted the names alphabetically, but forgot to apply the exact same sort logic to the phone numbers. Suddenly, the CEO's name was linked to the office microwave's extension, and the intern was listed as the Head of Legal. It was a chaotic afternoon of debugging that could have been avoided entirely if he'd just used a dictionary.
This is exactly why dictionaries are the gold standard for this kind of data. Instead of relying on the fragile order of a list, we tie a unique key—like a person's name—directly to their information. In this lesson, we're going to put that into practice by building a contact book. We aren't just talking about a simple name: phone pair, either; we're going to use nested dictionaries so each contact can hold multiple pieces of information, like an email and a physical address.
Organizing Data with Nested Dictionaries
When you're building a contact book, a single value usually isn't enough. You don't just want a phone number; you want a whole profile. I always recommend nesting a dictionary inside your main dictionary. This gives you a structured way to access specific details without having to concatenate strings or manage multiple dictionaries for different fields.
contacts = {
"Alice": {
"phone": "555-0101",
"email": "alice@example.com"
},
"Bob": {
"phone": "555-0202",
"email": "bob@example.com"
}
}
Now, if you want Alice's email, you just call contacts["Alice"]["email"]. It's clean, it's readable, and most importantly, it's scalable. If you decide later that you also need to store birthdays, you just add another key to the inner dictionary. You don't have to rewrite your entire data structure.
Managing the Book with Logic
A contact book is useless if you can't change it. In a real-world scenario, you'll spend more time updating and deleting data than you will creating it. When adding a new contact, remember that assigning a value to a key that doesn't exist yet will automatically create it. However, when searching for a contact, you have to be careful. If you try to access a key that isn't there, Python will throw a KeyError and crash your program.
I personally prefer using the .get() method for searches. It allows you to provide a default value—like "Contact not found"—instead of letting the app crash. It's a small habit, but it's what separates a script that "works on my machine" from professional-grade software.
# The risky way
print(contacts["Charlie"]) # This crashes if Charlie isn't there
# The professional way
contact_info = contacts.get("Charlie", "Contact not found")
print(contact_info)
Finally, removing a contact is straightforward with the del keyword or the .pop() method. I usually suggest .pop() because it returns the value of the item being removed, which is handy if you want to tell the user exactly which contact was deleted.
📋 Practical Task
The Personal Address Book Manager
Your task is to create a functional Contact Book program. Instead of just a static dictionary, you need to implement a system that allows a user to interact with their contacts via a loop.
Requirements:
- Initialize an empty dictionary called
address_book. - Create a loop that asks the user to choose an action: Add, Search, Delete, or Exit.
- Add: Ask for a name, a phone number, and an email. Store these as a nested dictionary inside
address_book. - Search: Ask for a name. If the name exists, print their phone and email. If not, print a friendly "Contact not found" message.
- Delete: Ask for a name. If it exists, remove the contact and confirm the deletion. If not, notify the user that the contact doesn't exist.
- Exit: Break the loop and end the program.
Pro Tip: Try to handle the case where a user might enter a name with different capitalization (e.g., "Alice" vs "alice") by using the .lower() or .title() method on the keys.
There are no comments for now.