Python Programming Examples Tutorial Index

Python Utility Programs

A contact book application is a practical tool to store, manage, and organize contact information. In this tutorial, you'll learn how to build a simple yet powerful Contact Management System in Python that uses JSON for persistent storage.



Understanding the Contact Book

Think of a contact book as a digital version of the address books we used to carry around. It's structured to store names, phone numbers, email addresses, and other details. This tutorial will teach you concepts like file handling, data management, and Python programming.

Key Features of the Contact Book Application

  • Class-Based Organization: The application is structured using a class, making it modular and reusable.
  • Persistent Storage: Contacts are saved to a JSON file, allowing data to persist between application runs.
  • Contact Management: Add, view, search, update, and delete contacts.
  • Flexible Search and Delete: Search contacts with partial names and delete specific matches.
  • Menu-Driven Interaction: Provides a simple and intuitive user interface.
  • Structured Data Storage: Stores contact details in a list of dictionaries.

Implementing the Contact Book Application

This section guides you through building the Contact Book in Python. The app's core features—adding, viewing, searching, updating, and deleting contacts—are all accessible via a straightforward menu-driven interface.

Project Setup and Required Libraries

To get started, you'll use Python's json and os modules for managing data and handling files. These modules are built into Python, so no additional installation is needed.

import json
import os

Defining the ContactBook Class

To keep your code organized, you'll structure it around a ContactBook class. This class will handle all the operations like adding, updating, and deleting contacts, as well as saving and loading data from a file.

class ContactBook:
    def __init__(self, filename='contacts.json'):
        """
        Initialize the contact book with a filename for storage.
        Load existing contacts from the file if available.
        """
        self.filename = filename
        self.contacts = self.load_contacts()

    def load_contacts(self):
        """
        Load contacts from the JSON file. 
        If the file does not exist, return an empty list.
        """
        if os.path.exists(self.filename):
            try:
                with open(self.filename, 'r') as file:
                    return json.load(file)
            except json.JSONDecodeError:
                print("Error reading contacts file. Starting with an empty contact book.")
                return []
        return []

    def save_contacts(self):
        """
        Save the current contact list to the JSON file.
        """
        with open(self.filename, 'w') as file:
            json.dump(self.contacts, file, indent=4)

Adding New Contacts

The add_contact method lets users add new contacts. It checks for duplicate phone numbers and email addresses before adding to ensure data consistency.

def add_contact(self):
    """
    Add a new contact to the contact book.
    Validates phone and email for duplicates before adding.
    """
    name = input("Enter contact name: ")
    phone = input("Enter phone number: ")
    email = input("Enter email address: ")

    # Check for duplicate phone/email
    duplicate_error = self.find_duplicate(phone, email)
    if duplicate_error:
        print(duplicate_error)
        return

    # Add the new contact
    self.contacts.append({'name': name, 'phone': phone, 'email': email})
    self.save_contacts()
    print(f"Contact '{name}' added successfully!")

Output:

Contact Book Menu:
1. View Contacts
2. Search Contact
3. Add Contact
4. Update Contact
5. Delete Contact
6. Exit
Enter your choice (1-6): 3
Enter contact name: Alex Johnson
Enter phone number: 7778889990
Enter email address: [email protected]
Contact 'Alex Johnson' added successfully!

Viewing Contacts

The view_contacts method displays all saved contacts in an easy-to-read format. If no contacts are found, let the user know.

def view_contacts(self):
    """
    Display all contacts in the contact book.
    """
    if not self.contacts:
        print("No contacts found.")
    else:
        for index, contact in enumerate(self.contacts, 1):
            print(f"{index}. Name: {contact['name']}, Phone: {contact['phone']}, Email: {contact['email']}")

Output:

Contact Book Menu:
1. View Contacts
2. Search Contact
3. Add Contact
4. Update Contact
5. Delete Contact
6. Exit
Enter your choice (1-6): 1
1. Name: John Doe, Phone: 1234567890, Email: [email protected]
2. Name: Priya Sharma, Phone: 9876543210, Email: [email protected]
3. Name: Alice Johnson, Phone: 5556667777, Email: [email protected]
4. Name: Alex Carter, Phone: 6665554443, Email: [email protected]
5. Name: Bob Williams, Phone: 4443332221, Email: [email protected]
6. Name: Emma Brown, Phone: 8889990001, Email: [email protected]
7. Name: Alex Johnson, Phone: 7778889990, Email: [email protected]

Searching for Contacts

The search_contact method allows users to search for contacts by name—either full or partial matches.

def search_contact(self, query):
    """
    Search for contacts by name.
    Displays all matching results.
    """
    results = [contact for contact in self.contacts if query.lower() in contact['name'].lower()]
    if results:
        for contact in results:
            print(f"Name: {contact['name']}, Phone: {contact['phone']}, Email: {contact['email']}")
    else:
        print("No matching contacts found.")

Output:

Contact Book Menu:
1. View Contacts
2. Search Contact
3. Add Contact
4. Update Contact
5. Delete Contact
6. Exit
Enter your choice (1-6): 2
Enter name to search: ale
Name: Alex Carter, Phone: 6665554443, Email: [email protected]
Name: Alex Johnson, Phone: 7778889990, Email: [email protected]

Updating Contact

The update_contact method lets users search for a contact by name, view matching results, and then select one to update. The method validates the updated phone number and email for duplicates before saving.

def update_contact(self, name):
    """
    Update an existing contact by name.
    Allows updating phone and email while checking for duplicates.
    """
    matches = [contact for contact in self.contacts if contact['name'].lower() == name.lower()]
    if not matches:
        print(f"No contacts found with the name '{name}'.")
        return

    # Show options to select contact
    print("\nMatching Contacts:")
    for index, contact in enumerate(matches, 1):
        print(f"{index}. Name: {contact['name']}, Phone: {contact['phone']}, Email: {contact['email']}")

    try:
        choice = int(input("Select the contact number to update (e.g., 1): ")) - 1
        if choice < 0 or choice >= len(matches):
            print("Invalid selection.")
            return
        selected_contact = matches[choice]
    except ValueError:
        print("Please enter a valid number.")
        return

    # Collect updated details
    new_phone = input(f"Enter new phone (or press Enter to keep '{selected_contact['phone']}'): ") or selected_contact['phone']
    new_email = input(f"Enter new email (or press Enter to keep '{selected_contact['email']}'): ") or selected_contact['email']

    # Check for duplicates
    duplicate_error = self.find_duplicate(new_phone, new_email, exclude_contact=selected_contact)
    if duplicate_error:
        print(duplicate_error)
        return

    # Apply updates
    selected_contact['phone'] = new_phone
    selected_contact['email'] = new_email
    self.save_contacts()
    print(f"Contact '{selected_contact['name']}' updated successfully!")

Output:

Contact Book Menu:
1. View Contacts
2. Search Contact
3. Add Contact
4. Update Contact
5. Delete Contact
6. Exit
Enter your choice (1-6): 4
Enter name to update: Alex Johnson

Matching Contacts:
1. Name: Alex Johnson, Phone: 7778889990, Email: [email protected]
Select the contact number to update (e.g., 1): 1
Enter new phone (or press Enter to keep '7778889990'): 0123456789
Enter new email (or press Enter to keep '[email protected]'):
Contact 'Alex Johnson' updated successfully!

Deleting Contacts

The delete_contact method lets users search for a contact by name, display matching results, and then select the specific contact to delete. This is particularly useful when multiple contacts have similar names, as the method first lists all matching entries, allowing the user to choose the exact contact to remove.

def delete_contact(self, query):
    """
    Delete a contact by name.
    Displays matching contacts and allows selection for deletion.
    """
    results = [contact for contact in self.contacts if query.lower() in contact['name'].lower()]
    if not results:
        print("No matching contacts found.")
        return

    print("\nMatching Contacts:")
    for index, contact in enumerate(results, 1):
        print(f"{index}. {contact['name']} - {contact['phone']}")

    try:
        choice = int(input("Enter the number of the contact to delete: ")) - 1
        if 0 <= choice < len(results):
            contact_to_delete = results[choice]
            self.contacts.remove(contact_to_delete)
            self.save_contacts()
            print(f"Contact {contact_to_delete['name']} deleted successfully!")
        else:
            print("Invalid selection.")
    except ValueError:
        print("Please enter a valid number.")

Output:

Contact Book Menu:
1. View Contacts
2. Search Contact
3. Add Contact
4. Update Contact
5. Delete Contact
6. Exit
Enter your choice (1-6): 5
Enter name to delete: bob

Matching Contacts:
1. Bob Williams - 4443332221
Enter the number of the contact to delete: 1
Contact Bob Williams deleted successfully!

Main Menu for User Interaction

The main method serves as the user-friendly interface for the contact book application. It provides a menu-driven system for viewing, searching, adding, updating, and deleting contacts. Users can select operations by entering the corresponding menu option.

def main():
    """
    Main menu loop for the contact book.
    Provides options for viewing, searching, adding, updating, and deleting contacts.
    """
    contact_book = ContactBook()

    while True:
        print("\nContact Book Menu:")
        print("1. View Contacts")
        print("2. Search Contact")
        print("3. Add Contact")
        print("4. Update Contact")
        print("5. Delete Contact")
        print("6. Exit")

        choice = input("Enter your choice (1-6): ")
        if choice == '1':
            contact_book.view_contacts()
        elif choice == '2':
            query = input("Enter name to search: ")
            contact_book.search_contact(query)
        elif choice == '3':
            contact_book.add_contact()
        elif choice == '4':
            name = input("Enter name to update: ")
            contact_book.update_contact(name)
        elif choice == '5':
            query = input("Enter name to delete: ")
            contact_book.delete_contact(query)
        elif choice == '6':
            print("Exiting Contact Book. Goodbye!")
            break
        else:
            print("Invalid choice. Try again.")

if __name__ == "__main__":
    main()

Output:

Contact Book Menu:
1. View Contacts
2. Search Contact
3. Add Contact
4. Update Contact
5. Delete Contact
6. Exit
Enter your choice (1-6):

Full Featured Application Code

Below is the complete implementation of the contact book application:

import json
import os

class ContactBook:
    def __init__(self, filename='contacts.json'):
        """
        Initialize the contact book with a filename for storage.
        Load existing contacts from the file if available.
        """
        self.filename = filename
        self.contacts = self.load_contacts()

    def load_contacts(self):
        """
        Load contacts from the JSON file. 
        If the file does not exist, return an empty list.
        """
        if os.path.exists(self.filename):
            try:
                with open(self.filename, 'r') as file:
                    return json.load(file)
            except json.JSONDecodeError:
                print("Error reading contacts file. Starting with an empty contact book.")
                return []
        return []

    def save_contacts(self):
        """
        Save the current contact list to the JSON file.
        """
        with open(self.filename, 'w') as file:
            json.dump(self.contacts, file, indent=4)

    def find_duplicate(self, phone, email, exclude_contact=None):
        """
        Check for duplicate phone numbers and email addresses in the contact list.
        Exclude a specific contact when checking (used during updates).
        """
        duplicate_messages = []

        for contact in self.contacts:
            if contact == exclude_contact:
                continue  # Skip the contact being updated
            if contact['phone'] == phone:
                duplicate_messages.append(f"Phone number '{phone}' already exists.")
            if contact['email'] == email:
                duplicate_messages.append(f"Email '{email}' already exists.")

        # Return combined message if there are duplicates
        return "\n".join(duplicate_messages) if duplicate_messages else None

    def view_contacts(self):
        """
        Display all contacts in the contact book.
        """
        if not self.contacts:
            print("No contacts found.")
        else:
            for index, contact in enumerate(self.contacts, 1):
                print(f"{index}. Name: {contact['name']}, Phone: {contact['phone']}, Email: {contact['email']}")

    def search_contact(self, query):
        """
        Search for contacts by name.
        Displays all matching results.
        """
        results = [contact for contact in self.contacts if query.lower() in contact['name'].lower()]
        if results:
            for contact in results:
                print(f"Name: {contact['name']}, Phone: {contact['phone']}, Email: {contact['email']}")
        else:
            print("No matching contacts found.")

    def add_contact(self):
        """
        Add a new contact to the contact book.
        Validates phone and email for duplicates before adding.
        """
        name = input("Enter contact name: ")
        phone = input("Enter phone number: ")
        email = input("Enter email address: ")

        # Check for duplicate phone/email
        duplicate_error = self.find_duplicate(phone, email)
        if duplicate_error:
            print(duplicate_error)
            return

        # Add the new contact
        self.contacts.append({'name': name, 'phone': phone, 'email': email})
        self.save_contacts()
        print(f"Contact '{name}' added successfully!")

    def update_contact(self, name):
        """
        Update an existing contact by name.
        Allows updating phone and email while checking for duplicates.
        """
        matches = [contact for contact in self.contacts if contact['name'].lower() == name.lower()]
        if not matches:
            print(f"No contacts found with the name '{name}'.")
            return

        # Show options to select contact
        print("\nMatching Contacts:")
        for index, contact in enumerate(matches, 1):
            print(f"{index}. Name: {contact['name']}, Phone: {contact['phone']}, Email: {contact['email']}")

        try:
            choice = int(input("Select the contact number to update (e.g., 1): ")) - 1
            if choice < 0 or choice >= len(matches):
                print("Invalid selection.")
                return
            selected_contact = matches[choice]
        except ValueError:
            print("Please enter a valid number.")
            return

        # Collect updated details
        new_phone = input(f"Enter new phone (or press Enter to keep '{selected_contact['phone']}'): ") or selected_contact['phone']
        new_email = input(f"Enter new email (or press Enter to keep '{selected_contact['email']}'): ") or selected_contact['email']

        # Check for duplicates
        duplicate_error = self.find_duplicate(new_phone, new_email, exclude_contact=selected_contact)
        if duplicate_error:
            print(duplicate_error)
            return

        # Apply updates
        selected_contact['phone'] = new_phone
        selected_contact['email'] = new_email
        self.save_contacts()
        print(f"Contact '{selected_contact['name']}' updated successfully!")

    def delete_contact(self, query):
        """
        Delete a contact by name.
        Displays matching contacts and allows selection for deletion.
        """
        results = [contact for contact in self.contacts if query.lower() in contact['name'].lower()]
        if not results:
            print("No matching contacts found.")
            return

        print("\nMatching Contacts:")
        for index, contact in enumerate(results, 1):
            print(f"{index}. {contact['name']} - {contact['phone']}")

        try:
            choice = int(input("Enter the number of the contact to delete: ")) - 1
            if 0 <= choice < len(results):
                contact_to_delete = results[choice]
                self.contacts.remove(contact_to_delete)
                self.save_contacts()
                print(f"Contact {contact_to_delete['name']} deleted successfully!")
            else:
                print("Invalid selection.")
        except ValueError:
            print("Please enter a valid number.")


def main():
    """
    Main menu loop for the contact book.
    Provides options for viewing, searching, adding, updating, and deleting contacts.
    """
    contact_book = ContactBook()

    while True:
        print("\nContact Book Menu:")
        print("1. View Contacts")
        print("2. Search Contact")
        print("3. Add Contact")
        print("4. Update Contact")
        print("5. Delete Contact")
        print("6. Exit")

        choice = input("Enter your choice (1-6): ")
        if choice == '1':
            contact_book.view_contacts()
        elif choice == '2':
            query = input("Enter name to search: ")
            contact_book.search_contact(query)
        elif choice == '3':
            contact_book.add_contact()
        elif choice == '4':
            name = input("Enter name to update: ")
            contact_book.update_contact(name)
        elif choice == '5':
            query = input("Enter name to delete: ")
            contact_book.delete_contact(query)
        elif choice == '6':
            print("Exiting Contact Book. Goodbye!")
            break
        else:
            print("Invalid choice. Try again.")


if __name__ == "__main__":
    main()

Conclusion

This tutorial demonstrated how to build a contact management system in Python using JSON for persistent storage. By completing this project, you learned about Python classes, file handling, and CRUD operations. Customize this application to explore additional features like advanced search filters or a graphical user interface.



Found This Page Useful? Share It!
Get the Latest Tutorials and Updates
Join us on Telegram