Python Dictionaries

Master key-value data structures for efficient data organization

šŸ“š What are Dictionaries?

Dictionaries are unordered, mutable collections that store data in key-value pairs. Each key must be unique, and they provide fast lookup times for accessing values.


# Creating a dictionary
person = {
    "name": "John",      # String value
    "age": 30,          # Integer value
    "height": 1.75,     # Float value
    "is_student": True  # Boolean value
}

# Accessing dictionary values
print(person["name"])    # Output: John
print(person.get("age")) # Output: 30
                                    
{}
Curly Braces
Key:Value
Pairs
Fast
Lookup

Creating Dictionaries

Learn different ways to create and initialize dictionaries:

Basic Dictionary Creation
# Empty dictionary
empty_dict = {}
print(f"Empty dictionary: {empty_dict}")

# Basic dictionary with different data types
person = {
    "name": "Alice",
    "age": 30,
    "city": "New York",
    "is_student": False
}
print(f"Person: {person}")

# Dictionary with mixed value types
student = {
    "id": 101,
    "name": "Bob",
    "courses": ["Math", "Physics", "Chemistry"],
    "grades": {"Math": "A", "Physics": "B+", "Chemistry": "A-"},
    "active": True
}
print(f"Student: {student}")

# Using dict() constructor
car = dict(brand="Toyota", model="Camry", year=2022, color="blue")
print(f"Car: {car}")

# Creating from lists of tuples
items = [("apple", 1.50), ("banana", 0.75), ("orange", 2.00)]
prices = dict(items)
print(f"Prices: {prices}")

Accessing Dictionary Values

Learn different methods to access and retrieve values from dictionaries:

šŸ”‘

Square Brackets

Direct access with key

person["name"]  # "Alice"
# Raises KeyError if key doesn't exist
šŸ›”ļø

get() Method

Safe access with default value

person.get("name")  # "Alice"
person.get("country", "Unknown")  # "Unknown"
Accessing Values Examples
person = {
    "name": "Alice",
    "age": 30,
    "city": "New York",
    "occupation": "Engineer"
}

# Direct access using square brackets
print(f"Name: {person['name']}")
print(f"Age: {person['age']}")

# Safe access using get() method
print(f"City: {person.get('city')}")
print(f"Country: {person.get('country', 'Not specified')}")

# Checking if key exists before accessing
if "salary" in person:
    print(f"Salary: {person['salary']}")
else:
    print("Salary information not available")

# Getting all keys, values, and items
print(f"Keys: {list(person.keys())}")
print(f"Values: {list(person.values())}")
print(f"Items: {list(person.items())}")

# Nested dictionary access
student = {
    "name": "Bob",
    "grades": {
        "Math": 95,
        "Science": 87,
        "English": 92
    }
}

print(f"Math grade: {student['grades']['Math']}")
print(f"Science grade: {student.get('grades', {}).get('Science', 'N/A')}")

Modifying Dictionaries

Dictionaries are mutable, so you can change, add, and remove items:

Dictionary Modification
car = {
    "brand": "Ford",
    "model": "Mustang",
    "year": 1964
}
print(f"Original car: {car}")

# Modify existing value
car["year"] = 2020
print(f"Updated year: {car}")

# Add new key-value pair
car["color"] = "red"
car["engine"] = "V8"
print(f"Added properties: {car}")

# Update multiple items at once
car.update({"mileage": 15000, "condition": "excellent"})
print(f"After update(): {car}")

# Update from another dictionary
additional_info = {"owner": "John", "insurance": "active"}
car.update(additional_info)
print(f"Added owner info: {car}")

# Removing items
print("\nRemoving items:")

# Remove specific key with pop()
removed_mileage = car.pop("mileage")
print(f"Removed mileage: {removed_mileage}")
print(f"Car after pop: {car}")

# Remove with default value if key doesn't exist
removed_warranty = car.pop("warranty", "No warranty info")
print(f"Removed warranty: {removed_warranty}")

# Remove last inserted item with popitem()
removed_item = car.popitem()
print(f"Removed last item: {removed_item}")
print(f"Car after popitem: {car}")

# Remove specific key with del
del car["condition"]
print(f"After del: {car}")

# Clear all items
backup_car = car.copy()  # Make a backup
car.clear()
print(f"After clear(): {car}")
print(f"Backup: {backup_car}")

Dictionary Methods and Views

Explore powerful dictionary methods for data manipulation:

Dictionary Methods
inventory = {
    "apples": 50,
    "bananas": 30,
    "oranges": 25,
    "grapes": 40
}

print("Original inventory:", inventory)

# keys(), values(), items() - return view objects
print(f"Keys: {list(inventory.keys())}")
print(f"Values: {list(inventory.values())}")
print(f"Items: {list(inventory.items())}")

# setdefault() - get value or set default if key doesn't exist
pears = inventory.setdefault("pears", 0)
print(f"Pears (setdefault): {pears}")
print(f"Inventory after setdefault: {inventory}")

# fromkeys() - create dictionary with same value for multiple keys
fruits = ["mango", "kiwi", "pineapple"]
new_fruits = dict.fromkeys(fruits, 0)
print(f"New fruits with default values: {new_fruits}")

# copy() - create shallow copy
inventory_backup = inventory.copy()
print(f"Backup created: {inventory_backup}")

# Demonstrate view objects are dynamic
print("\nDemonstrating dynamic views:")
keys_view = inventory.keys()
print(f"Keys view before adding: {list(keys_view)}")

inventory["strawberries"] = 15
print(f"Keys view after adding: {list(keys_view)}")  # View updates automatically

# Dictionary comprehension
squared_numbers = {x: x**2 for x in range(1, 6)}
print(f"Squared numbers: {squared_numbers}")

# Filter dictionary using comprehension
high_stock = {fruit: qty for fruit, qty in inventory.items() if qty > 30}
print(f"High stock items: {high_stock}")

Iterating Through Dictionaries

Learn different ways to loop through dictionary data:

Dictionary Iteration
student_grades = {
    "Alice": 95,
    "Bob": 87,
    "Charlie": 92,
    "Diana": 98,
    "Eve": 89
}

# Method 1: Iterate through keys (default)
print("Method 1 - Keys only:")
for student in student_grades:
    print(f"{student}: {student_grades[student]}")

print("\nMethod 2 - Keys explicitly:")
for student in student_grades.keys():
    print(f"{student}: {student_grades[student]}")

# Method 3: Iterate through values
print("\nMethod 3 - Values only:")
for grade in student_grades.values():
    print(f"Grade: {grade}")

# Method 4: Iterate through key-value pairs
print("\nMethod 4 - Key-value pairs:")
for student, grade in student_grades.items():
    print(f"{student} scored {grade}")

# Method 5: With enumerate for numbering
print("\nMethod 5 - With numbering:")
for i, (student, grade) in enumerate(student_grades.items(), 1):
    status = "Excellent" if grade >= 90 else "Good" if grade >= 80 else "Needs Improvement"
    print(f"{i}. {student}: {grade} ({status})")

# Practical example: Grade analysis
print("\n" + "="*40)
print("GRADE ANALYSIS")
print("="*40)

total_students = len(student_grades)
total_score = sum(student_grades.values())
average_grade = total_score / total_students

print(f"Total students: {total_students}")
print(f"Average grade: {average_grade:.1f}")

# Find highest and lowest scores
highest_student = max(student_grades, key=student_grades.get)
lowest_student = min(student_grades, key=student_grades.get)

print(f"Highest score: {highest_student} ({student_grades[highest_student]})")
print(f"Lowest score: {lowest_student} ({student_grades[lowest_student]})")

# Count grades by category
grade_categories = {"A": 0, "B": 0, "C": 0, "D": 0, "F": 0}

for student, grade in student_grades.items():
    if grade >= 90:
        grade_categories["A"] += 1
    elif grade >= 80:
        grade_categories["B"] += 1
    elif grade >= 70:
        grade_categories["C"] += 1
    elif grade >= 60:
        grade_categories["D"] += 1
    else:
        grade_categories["F"] += 1

print("\nGrade distribution:")
for letter_grade, count in grade_categories.items():
    if count > 0:
        percentage = (count / total_students) * 100
        print(f"  {letter_grade}: {count} students ({percentage:.1f}%)")

Real-World Example: User Profile Management

Build a comprehensive user management system using dictionaries:

User Profile System
class UserProfileManager:
    """Manage user profiles using dictionaries."""
    
    def __init__(self):
        self.users = {}
        self.next_id = 1
    
    def create_profile(self, name, email, age, interests=None):
        """Create a new user profile."""
        if interests is None:
            interests = []
        
        user_id = f"user_{self.next_id:03d}"
        self.next_id += 1
        
        profile = {
            "id": user_id,
            "name": name,
            "email": email,
            "age": age,
            "interests": interests,
            "created_date": "2024-01-15",  # In real app, use datetime
            "login_count": 0,
            "is_active": True,
            "settings": {
                "notifications": True,
                "privacy": "public",
                "theme": "light"
            }
        }
        
        self.users[user_id] = profile
        print(f"āœ… Profile created for {name} (ID: {user_id})")
        return user_id
    
    def get_profile(self, user_id):
        """Get user profile by ID."""
        return self.users.get(user_id, None)
    
    def update_profile(self, user_id, **updates):
        """Update user profile with new information."""
        if user_id not in self.users:
            print(f"āŒ User {user_id} not found")
            return False
        
        profile = self.users[user_id]
        
        # Update basic fields
        for key, value in updates.items():
            if key in profile:
                old_value = profile[key]
                profile[key] = value
                print(f"šŸ“ Updated {key}: {old_value} → {value}")
            else:
                print(f"āš ļø Field '{key}' not found in profile")
        
        return True
    
    def add_interest(self, user_id, interest):
        """Add an interest to user's profile."""
        profile = self.get_profile(user_id)
        if profile:
            if interest not in profile["interests"]:
                profile["interests"].append(interest)
                print(f"āž• Added interest '{interest}' to {profile['name']}")
            else:
                print(f"ā„¹ļø Interest '{interest}' already exists")
        else:
            print(f"āŒ User {user_id} not found")
    
    def update_settings(self, user_id, **settings):
        """Update user settings."""
        profile = self.get_profile(user_id)
        if profile:
            profile["settings"].update(settings)
            print(f"āš™ļø Settings updated for {profile['name']}")
        else:
            print(f"āŒ User {user_id} not found")
    
    def deactivate_user(self, user_id):
        """Deactivate a user account."""
        profile = self.get_profile(user_id)
        if profile:
            profile["is_active"] = False
            print(f"šŸ”’ Deactivated account for {profile['name']}")
        else:
            print(f"āŒ User {user_id} not found")
    
    def search_users(self, **criteria):
        """Search users by various criteria."""
        results = []
        
        for user_id, profile in self.users.items():
            match = True
            
            for key, value in criteria.items():
                if key == "min_age":
                    if profile["age"] < value:
                        match = False
                        break
                elif key == "max_age":
                    if profile["age"] > value:
                        match = False
                        break
                elif key == "interest":
                    if value not in profile["interests"]:
                        match = False
                        break
                elif key == "is_active":
                    if profile["is_active"] != value:
                        match = False
                        break
                elif key in profile:
                    if profile[key] != value:
                        match = False
                        break
            
            if match:
                results.append(profile)
        
        return results
    
    def get_statistics(self):
        """Get user statistics."""
        if not self.users:
            return {"message": "No users found"}
        
        total_users = len(self.users)
        active_users = sum(1 for profile in self.users.values() if profile["is_active"])
        
        ages = [profile["age"] for profile in self.users.values()]
        avg_age = sum(ages) / len(ages)
        
        # Count interests
        all_interests = []
        for profile in self.users.values():
            all_interests.extend(profile["interests"])
        
        interest_count = {}
        for interest in all_interests:
            interest_count[interest] = interest_count.get(interest, 0) + 1
        
        # Most popular interest
        popular_interest = max(interest_count, key=interest_count.get) if interest_count else "None"
        
        return {
            "total_users": total_users,
            "active_users": active_users,
            "inactive_users": total_users - active_users,
            "average_age": round(avg_age, 1),
            "most_popular_interest": popular_interest,
            "interest_distribution": interest_count
        }
    
    def display_profile(self, user_id):
        """Display formatted user profile."""
        profile = self.get_profile(user_id)
        if not profile:
            print(f"āŒ User {user_id} not found")
            return
        
        print(f"\n{'='*50}")
        print(f"USER PROFILE: {profile['name'].upper()}")
        print(f"{'='*50}")
        print(f"ID: {profile['id']}")
        print(f"Email: {profile['email']}")
        print(f"Age: {profile['age']}")
        print(f"Status: {'🟢 Active' if profile['is_active'] else 'šŸ”“ Inactive'}")
        print(f"Login Count: {profile['login_count']}")
        print(f"Created: {profile['created_date']}")
        
        if profile['interests']:
            print(f"Interests: {', '.join(profile['interests'])}")
        else:
            print("Interests: None")
        
        print(f"\nSettings:")
        for key, value in profile['settings'].items():
            print(f"  {key.title()}: {value}")

# Example usage
print("šŸš€ User Profile Management System")
print("="*50)

# Create manager instance
manager = UserProfileManager()

# Create user profiles
alice_id = manager.create_profile("Alice Johnson", "[email protected]", 28, ["reading", "hiking", "photography"])
bob_id = manager.create_profile("Bob Smith", "[email protected]", 35, ["gaming", "cooking"])
charlie_id = manager.create_profile("Charlie Brown", "[email protected]", 22, ["music", "photography", "travel"])

# Display a profile
manager.display_profile(alice_id)

# Update profile
manager.update_profile(alice_id, age=29, login_count=5)

# Add interests
manager.add_interest(bob_id, "photography")
manager.add_interest(charlie_id, "hiking")

# Update settings
manager.update_settings(alice_id, theme="dark", privacy="private")

# Search users
print(f"\nšŸ” SEARCH RESULTS")
print("="*30)

photo_enthusiasts = manager.search_users(interest="photography")
print(f"Photography enthusiasts: {len(photo_enthusiasts)}")
for user in photo_enthusiasts:
    print(f"  - {user['name']} (Age: {user['age']})")

young_users = manager.search_users(max_age=30)
print(f"\nUsers under 30: {len(young_users)}")
for user in young_users:
    print(f"  - {user['name']} (Age: {user['age']})")

# Get statistics
print(f"\nšŸ“Š USER STATISTICS")
print("="*30)
stats = manager.get_statistics()
for key, value in stats.items():
    if key == "interest_distribution":
        print(f"Interest Distribution:")
        for interest, count in value.items():
            print(f"  {interest}: {count} users")
    else:
        print(f"{key.replace('_', ' ').title()}: {value}")

# Deactivate a user
manager.deactivate_user(charlie_id)

# Final statistics
print(f"\nšŸ“Š FINAL STATISTICS")
print("="*30)
final_stats = manager.get_statistics()
print(f"Active Users: {final_stats['active_users']}")
print(f"Inactive Users: {final_stats['inactive_users']}")