Of course! Creating a contact list is a classic and excellent project for learning Python. It touches on fundamental concepts like data structures, user input, loops, and file I/O.

I'll guide you through this in three steps:
- A Basic Command-Line Version: A simple, in-memory contact list.
- An Enhanced Version: Adding features like search, update, and delete.
- A Persistent Version: Saving your contacts to a file so they aren't lost when the program closes.
The Basic Command-Line Contact List
This version will store contacts in a Python dictionary. Each contact will be another dictionary with keys like name, phone, and email.
Core Concepts:
- Dictionary: To store contacts (
{name: {details}}). whileloop: To keep the program running.if/elif/else: To handle user menu choices.input(): To get user data.print(): To display information.
The Code
# A simple, in-memory contact list
contacts = {}
def add_contact():
"""Adds a new contact to the list."""
name = input("Enter contact name: ")
phone = input("Enter contact phone number: ")
email = input("Enter contact email: ")
# Store the contact details in a nested dictionary
contacts[name] = {
'phone': phone,
'email': email
}
print(f"Contact '{name}' added successfully!\n")
def view_contacts():
"""Displays all saved contacts."""
if not contacts:
print("No contacts found.\n")
return
print("--- Contact List ---")
for name, details in contacts.items():
print(f"Name: {name}")
print(f" Phone: {details['phone']}")
print(f" Email: {details['email']}")
print("-" * 20)
print()
def main():
"""Main function to run the contact list application."""
print("Welcome to the Contact List App!")
while True:
print("Please choose an option:")
print("1. Add a new contact")
print("2. View all contacts")
print("3. Exit")
choice = input("Enter your choice (1-3): ")
if choice == '1':
add_contact()
elif choice == '2':
view_contacts()
elif choice == '3':
print("Goodbye!")
break
else:
print("Invalid choice. Please enter a number between 1 and 3.\n")
# This ensures the main() function runs only when the script is executed directly
if __name__ == "__main__":
main()
How to Run It:
- Save the code as a Python file (e.g.,
contact_list.py). - Open your terminal or command prompt.
- Navigate to the directory where you saved the file.
- Run the script:
python contact_list.py
Enhanced Version (Search, Update, Delete)
This version builds on the first one by adding more functionality. It also introduces a helper function to find a contact, which avoids repeating code.
New Features:
- Search for a contact by name.
- Update an existing contact's information.
- Delete a contact from the list.
The Code
# An enhanced contact list with search, update, and delete
contacts = {}
def find_contact(name):
"""Helper function to find a contact and return its details."""
return contacts.get(name)
def add_contact():
name = input("Enter contact name: ")
if find_contact(name):
print(f"Contact '{name}' already exists. Use the 'Update' option to modify it.\n")
return
phone = input("Enter contact phone number: ")
email = input("Enter contact email: ")
contacts[name] = {'phone': phone, 'email': email}
print(f"Contact '{name}' added successfully!\n")
def view_contacts():
if not contacts:
print("No contacts found.\n")
return
print("--- Contact List ---")
for name, details in contacts.items():
print(f"Name: {name}")
print(f" Phone: {details['phone']}")
print(f" Email: {details['email']}")
print("-" * 20)
print()
def search_contact():
name = input("Enter the name of the contact to search: ")
contact = find_contact(name)
if contact:
print(f"--- Found Contact ---")
print(f"Name: {name}")
print(f"Phone: {contact['phone']}")
print(f"Email: {contact['email']}\n")
else:
print(f"Contact '{name}' not found.\n")
def update_contact():
name = input("Enter the name of the contact to update: ")
contact = find_contact(name)
if contact:
print(f"Updating contact for '{name}'. Press Enter to keep the current value.")
new_phone = input(f"Enter new phone number ({contact['phone']}): ") or contact['phone']
new_email = input(f"Enter new email ({contact['email']}): ") or contact['email']
contacts[name] = {'phone': new_phone, 'email': new_email}
print(f"Contact '{name}' updated successfully!\n")
else:
print(f"Contact '{name}' not found. Cannot update.\n")
def delete_contact():
name = input("Enter the name of the contact to delete: ")
if find_contact(name):
del contacts[name]
print(f"Contact '{name}' deleted successfully!\n")
else:
print(f"Contact '{name}' not found. Cannot delete.\n")
def main():
print("Welcome to the Enhanced Contact List App!")
while True:
print("\nPlease choose an option:")
print("1. Add a new contact")
print("2. View all contacts")
print("3. Search for a contact")
print("4. Update a contact")
print("5. Delete a contact")
print("6. Exit")
choice = input("Enter your choice (1-6): ")
if choice == '1':
add_contact()
elif choice == '2':
view_contacts()
elif choice == '3':
search_contact()
elif choice == '4':
update_contact()
elif choice == '5':
delete_contact()
elif choice == '6':
print("Goodbye!")
break
else:
print("Invalid choice. Please enter a number between 1 and 6.\n")
if __name__ == "__main__":
main()
Persistent Version (Saving to a File)
The biggest problem with the previous versions is that all contacts are lost when the program ends. We can fix this by saving the contacts to a file. We'll use the JSON format because it's human-readable and works perfectly with Python dictionaries.

New Concepts:
jsonmodule: To convert Python dictionaries to JSON strings (serialization) and back (deserialization).try...exceptblock: To gracefully handle cases where the data file doesn't exist yet.with open(...): The best practice for opening files, as it automatically closes them for you.
The Code
This version combines all features from the enhanced list and adds file handling.
import json
import os
# Define the filename for storing contacts
CONTACTS_FILE = "contacts.json"
# Load contacts from the file when the program starts
def load_contacts():
"""Loads contacts from a JSON file."""
if os.path.exists(CONTACTS_FILE):
try:
with open(CONTACTS_FILE, 'r') as f:
return json.load(f)
except (json.JSONDecodeError, IOError):
# If the file is corrupted or can't be read, start fresh
print(f"Warning: Could not read {CONTACTS_FILE}. Starting with an empty contact list.")
return {}
return {}
# Save contacts to the file whenever they change
def save_contacts(contacts_to_save):
"""Saves contacts to a JSON file."""
with open(CONTACTS_FILE, 'w') as f:
json.dump(contacts_to_save, f, indent=4) # indent=4 makes the file readable
# --- All other functions from the enhanced version are the same ---
# (add_contact, view_contacts, search_contact, update_contact, delete_contact)
# Just make sure they use the global `contacts` variable.
# --- A slightly modified main function ---
def main():
"""Main function to run the contact list application."""
# Load contacts at the very beginning
global contacts
contacts = load_contacts()
print("Welcome to the Persistent Contact List App!")
while True:
print("\nPlease choose an option:")
print("1. Add a new contact")
print("2. View all contacts")
print("3. Search for a contact")
print("4. Update a contact")
print("5. Delete a contact")
print("6. Exit")
choice = input("Enter your choice (1-6): ")
if choice == '1':
add_contact()
save_contacts(contacts) # Save after adding
elif choice == '2':
view_contacts()
elif choice == '3':
search_contact()
elif choice == '4':
update_contact()
save_contacts(contacts) # Save after updating
elif choice == '5':
delete_contact()
save_contacts(contacts) # Save after deleting
elif choice == '6':
print("Goodbye!")
break
else:
print("Invalid choice. Please enter a number between 1 and 6.\n")
# Note: For this to work seamlessly, you need to declare `contacts` as global
# inside each function that modifies it (add, update, delete).
# Here is the corrected `add_contact` function as an example:
def add_contact():
global contacts # Declare that we're using the global contacts variable
name = input("Enter contact name: ")
if find_contact(name):
print(f"Contact '{name}' already exists. Use the 'Update' option to modify it.\n")
return
phone = input("Enter contact phone number: ")
email = input("Enter contact email: ")
contacts[name] = {'phone': phone, 'email': email}
print(f"Contact '{name}' added successfully!\n")
# You would need to add `global contacts` to update_contact and delete_contact as well.
# A better way to handle this is to pass the `contacts` dictionary as an argument
# to each function, but for simplicity in this tutorial, the global approach is shown.
if __name__ == "__main__":
main()
Next Steps and Improvements
This is a great foundation. Here are some ideas to take this project even further:
- Object-Oriented Programming (OOP): Refactor the code using classes. You could have a
Contactclass to hold the details of a single person and aContactListclass to manage all the contacts and the file operations. This is a more scalable and organized approach. - Data Validation: Add checks to ensure phone numbers are numeric or that email addresses contain an "@" symbol.
- More Details: Allow users to add more fields like
address,birthday, ornotes. - Command-Line Arguments: Use Python's
argparsemodule to allow users to perform actions from the command line without opening an interactive prompt (e.g.,python contact_list.py search "John Doe"). - Graphical User Interface (GUI): Use a library like Tkinter (built-in), PyQt, or Kivy to create a visual application with windows, buttons, and text boxes.

