Of course! Here is a comprehensive guide to creating a Python Address Book, starting with a simple version and building up to a more feature-rich, file-based application.

Part 1: A Simple In-Memory Address Book
This version stores contacts in a Python dictionary. It's a great starting point to understand the core logic.
The Code
# A simple in-memory address book
def add_contact(address_book):
"""Adds a new contact to the address book."""
print("\n--- Add a New Contact ---")
name = input("Enter name: ")
phone = input("Enter phone number: ")
email = input("Enter email address: ")
# Store the contact details in a dictionary
contact = {
"name": name,
"phone": phone,
"email": email
}
# Use the name as the key for easy lookup
address_book[name] = contact
print(f"Contact '{name}' added successfully!")
def view_all_contacts(address_book):
"""Displays all contacts in the address book."""
print("\n--- All Contacts ---")
if not address_book:
print("No contacts found.")
return
for name, details in address_book.items():
print(f"Name: {name}")
print(f" Phone: {details['phone']}")
print(f" Email: {details['email']}")
print("-" * 20)
def search_contact(address_book):
"""Searches for a contact by name."""
print("\n--- Search for a Contact ---")
search_term = input("Enter the name to search for: ")
found = False
for name, details in address_book.items():
# Case-insensitive search
if search_term.lower() in name.lower():
print("\n--- Contact Found ---")
print(f"Name: {name}")
print(f" Phone: {details['phone']}")
print(f" Email: {details['email']}")
found = True
if not found:
print(f"No contact found with the name '{search_term}'.")
def delete_contact(address_book):
"""Deletes a contact by name."""
print("\n--- Delete a Contact ---")
name_to_delete = input("Enter the name of the contact to delete: ")
if name_to_delete in address_book:
del address_book[name_to_delete]
print(f"Contact '{name_to_delete}' deleted successfully.")
else:
print(f"Contact '{name_to_delete}' not found.")
def main():
"""Main function to run the address book application."""
address_book = {} # The address book is a dictionary
while True:
print("\n===== Address Book Menu =====")
print("1. Add Contact")
print("2. View All Contacts")
print("3. Search Contact")
print("4. Delete Contact")
print("5. Exit")
choice = input("Enter your choice (1-5): ")
if choice == '1':
add_contact(address_book)
elif choice == '2':
view_all_contacts(address_book)
elif choice == '3':
search_contact(address_book)
elif choice == '4':
delete_contact(address_book)
elif choice == '5':
print("Exiting Address Book. Goodbye!")
break
else:
print("Invalid choice. Please enter a number between 1 and 5.")
# Run the main function when the script is executed
if __name__ == "__main__":
main()
How to Run It
- Save the code as a Python file (e.g.,
simple_address_book.py). - Run it from your terminal:
python simple_address_book.py - Follow the on-screen menu.
Limitation
The biggest problem with this version is that all data is lost when you close the program. The address_book dictionary exists only in the computer's memory.
Part 2: A File-Based Address Book (Persistent Storage)
This version improves upon the first by saving contacts to a file. This way, your address book will remember the contacts between sessions. We'll use Python's built-in json module, which is perfect for storing structured data like dictionaries.
The Code
import json
import os
# File to store the address book
ADDRESS_BOOK_FILE = "address_book.json"
def load_address_book():
"""Loads the address book from a JSON file."""
if os.path.exists(ADDRESS_BOOK_FILE):
try:
with open(ADDRESS_BOOK_FILE, 'r') as f:
return json.load(f)
except (json.JSONDecodeError, FileNotFoundError):
# If the file is empty or corrupted, start fresh
return {}
else:
# If the file doesn't exist, create a new one
return {}
def save_address_book(address_book):
"""Saves the address book to a JSON file."""
with open(ADDRESS_BOOK_FILE, 'w') as f:
json.dump(address_book, f, indent=4) # indent=4 makes the file readable
# --- Functions from Part 1 are mostly the same ---
def add_contact(address_book):
"""Adds a new contact to the address book and saves it."""
print("\n--- Add a New Contact ---")
name = input("Enter name: ")
phone = input("Enter phone number: ")
email = input("Enter email address: ")
if name in address_book:
print(f"Contact '{name}' already exists. Use 'Update Contact' instead.")
return
contact = {"name": name, "phone": phone, "email": email}
address_book[name] = contact
save_address_book(address_book)
print(f"Contact '{name}' added successfully!")
def view_all_contacts(address_book):
"""Displays all contacts in the address book."""
print("\n--- All Contacts ---")
if not address_book:
print("No contacts found.")
return
for name, details in address_book.items():
print(f"Name: {details['name']}") # Use details['name'] for consistency
print(f" Phone: {details['phone']}")
print(f" Email: {details['email']}")
print("-" * 20)
def search_contact(address_book):
"""Searches for a contact by name."""
print("\n--- Search for a Contact ---")
search_term = input("Enter the name to search for: ")
found = False
for name, details in address_book.items():
if search_term.lower() in name.lower():
print("\n--- Contact Found ---")
print(f"Name: {details['name']}")
print(f" Phone: {details['phone']}")
print(f" Email: {details['email']}")
found = True
if not found:
print(f"No contact found with the name '{search_term}'.")
def delete_contact(address_book):
"""Deletes a contact by name and saves the change."""
print("\n--- Delete a Contact ---")
name_to_delete = input("Enter the name of the contact to delete: ")
if name_to_delete in address_book:
del address_book[name_to_delete]
save_address_book(address_book)
print(f"Contact '{name_to_delete}' deleted successfully.")
else:
print(f"Contact '{name_to_delete}' not found.")
def update_contact(address_book):
"""Updates an existing contact's details."""
print("\n--- Update a Contact ---")
name_to_update = input("Enter the name of the contact to update: ")
if name_to_update in address_book:
contact = address_book[name_to_update]
print(f"Current details for {name_to_update}:")
print(f" Phone: {contact['phone']}")
print(f" Email: {contact['email']}")
print("\nEnter new details (leave blank to keep current):")
new_phone = input(f"New phone [{contact['phone']}]: ") or contact['phone']
new_email = input(f"New email [{contact['email']}]: ") or contact['email']
contact['phone'] = new_phone
contact['email'] = new_email
save_address_book(address_book)
print(f"Contact '{name_to_update}' updated successfully.")
else:
print(f"Contact '{name_to_update}' not found.")
def main():
"""Main function to run the address book application."""
address_book = load_address_book()
while True:
print("\n===== Address Book Menu =====")
print("1. Add Contact")
print("2. View All Contacts")
print("3. Search Contact")
print("4. Update Contact") # New option
print("5. Delete Contact")
print("6. Exit")
choice = input("Enter your choice (1-6): ")
if choice == '1':
add_contact(address_book)
elif choice == '2':
view_all_contacts(address_book)
elif choice == '3':
search_contact(address_book)
elif choice == '4':
update_contact(address_book)
elif choice == '5':
delete_contact(address_book)
elif choice == '6':
print("Exiting Address Book. Goodbye!")
break
else:
print("Invalid choice. Please enter a number between 1 and 6.")
if __name__ == "__main__":
main()
Key Improvements in Version 2
- File Handling (
jsonmodule):load_address_book(): Reads theaddress_book.jsonfile when the program starts. If the file doesn't exist, it gracefully creates an empty dictionary.save_address_book(): Writes the current state of theaddress_bookdictionary to the file.json.dump(address_book, f, indent=4)makes the saved file human-readable.
- Persistent Data: Now, every time you add, update, or delete a contact, the
save_address_book()function is called, saving your changes to the file. - Update Function: Added a new
update_contact()function, which is a common and useful feature. - Consistent Display: The
view_all_contactsnow printsdetails['name']to ensure consistency if you ever change the key.
How to Run It
- Save the code as
address_book.py. - Run it:
python address_book.py. - After adding a few contacts and exiting, you will see a new file named
address_book.jsonin the same directory. You can open it with any text editor to see your data stored in JSON format.
Part 3: Object-Oriented Approach (More Advanced)
For larger applications, organizing code into classes is a best practice. This version encapsulates the address book's logic and data within a class.

The Code
import json
import os
class Contact:
"""Represents a single contact."""
def __init__(self, name, phone, email):
self.name = name
self.phone = phone
self.email = email
def to_dict(self):
"""Converts the contact object to a dictionary for JSON serialization."""
return {"name": self.name, "phone": self.phone, "email": self.email}
class AddressBook:
"""Manages a collection of contacts."""
def __init__(self, filename="address_book.json"):
self.filename = filename
self.contacts = {} # Using a dictionary for fast lookups by name
self.load()
def load(self):
"""Loads contacts from the JSON file."""
if os.path.exists(self.filename):
try:
with open(self.filename, 'r') as f:
data = json.load(f)
# Rebuild Contact objects from the dictionary data
for name, details in data.items():
self.contacts[name] = Contact(name, details['phone'], details['email'])
except (json.JSONDecodeError, FileNotFoundError):
self.contacts = {}
def save(self):
"""Saves all contacts to the JSON file."""
# Convert all Contact objects to dictionaries before saving
data = {name: contact.to_dict() for name, contact in self.contacts.items()}
with open(self.filename, 'w') as f:
json.dump(data, f, indent=4)
def add_contact(self, contact):
"""Adds a new contact if the name doesn't already exist."""
if contact.name in self.contacts:
print(f"Error: Contact '{contact.name}' already exists.")
return False
self.contacts[contact.name] = contact
self.save()
print(f"Contact '{contact.name}' added successfully.")
return True
def view_all_contacts(self):
"""Displays all contacts."""
if not self.contacts:
print("\nNo contacts found.")
return
print("\n--- All Contacts ---")
for contact in self.contacts.values():
print(f"Name: {contact.name}")
print(f" Phone: {contact.phone}")
print(f" Email: {contact.email}")
print("-" * 20)
def search_contact(self, search_term):
"""Searches for a contact by name."""
found = False
print(f"\n--- Search Results for '{search_term}' ---")
for contact in self.contacts.values():
if search_term.lower() in contact.name.lower():
print(f"Name: {contact.name}")
print(f" Phone: {contact.phone}")
print(f" Email: {contact.email}")
print("-" * 20)
found = True
if not found:
print(f"No contacts found matching '{search_term}'.")
def delete_contact(self, name):
"""Deletes a contact by name."""
if name in self.contacts:
del self.contacts[name]
self.save()
print(f"Contact '{name}' deleted successfully.")
return True
else:
print(f"Error: Contact '{name}' not found.")
return False
def update_contact(self, name):
"""Updates an existing contact's details."""
if name not in self.contacts:
print(f"Error: Contact '{name}' not found.")
return
contact = self.contacts[name]
print(f"\nUpdating details for {name}:")
print(f" Current Phone: {contact.phone}")
print(f" Current Email: {contact.email}")
new_phone = input(f"Enter new phone (or leave blank to keep '{contact.phone}'): ") or contact.phone
new_email = input(f"Enter new email (or leave blank to keep '{contact.email}'): ") or contact.email
contact.phone = new_phone
contact.email = new_email
self.save()
print(f"Contact '{name}' updated successfully.")
# --- Main Application Logic ---
def main():
"""Runs the command-line interface for the Address Book."""
address_book = AddressBook()
while True:
print("\n===== Address Book Menu =====")
print("1. Add Contact")
print("2. View All Contacts")
print("3. Search Contact")
print("4. Update Contact")
print("5. Delete Contact")
print("6. Exit")
choice = input("Enter your choice (1-6): ")
if choice == '1':
print("\n--- Add a New Contact ---")
name = input("Enter name: ")
phone = input("Enter phone number: ")
email = input("Enter email address: ")
new_contact = Contact(name, phone, email)
address_book.add_contact(new_contact)
elif choice == '2':
address_book.view_all_contacts()
elif choice == '3':
search_term = input("Enter the name to search for: ")
address_book.search_contact(search_term)
elif choice == '4':
name = input("Enter the name of the contact to update: ")
address_book.update_contact(name)
elif choice == '5':
name = input("Enter the name of the contact to delete: ")
address_book.delete_contact(name)
elif choice == '6':
print("Exiting Address Book. Goodbye!")
break
else:
print("Invalid choice. Please enter a number between 1 and 6.")
if __name__ == "__main__":
main()
Why Object-Oriented?
- Encapsulation: The
AddressBookclass manages its own data (self.contacts) and the logic to manipulate it (add,save, etc.). Themainfunction doesn't need to know how it works, only what it can do. - Organization: Code is split into logical classes (
Contact,AddressBook), making it easier to read, maintain, and expand. - Scalability: It's much easier to add new features to this structure (e.g., adding an
addressfield to theContactclass) without cluttering the main application loop.

