What is a Python Dictionary?
Core Characteristics
Key-Value Pairs
Collections of unique keys mapping to values, like a real dictionary
Mutable & Dynamic
Can add, remove, and modify key-value pairs after creation
Insertion Ordered (Python 3.7+)
Maintains the order in which items were added
Basic Dictionary Example
# Creating a student dictionary
student = {
"name": "Alice Johnson",
"age": 21,
"course": "Computer Science",
"grades": {"math": 95, "python": 98, "algorithms": 92},
"hobbies": ["coding", "reading", "gaming"],
"is_active": True
}
# Accessing values
print(student["name"]) # Alice Johnson
print(student.get("age")) # 21 (safer method)
print(student["grades"]["python"]) # 98 (nested access)
# Dictionary properties
print(type(student)) #
print(len(student)) # 6 (number of key-value pairs)
print(student.keys()) # dict_keys(['name', 'age', ...])
Key Rules for Dictionary Keys
✅ Allowed Key Types
- Strings:
"name" - Integers:
42 - Floats:
3.14 - Tuples (if all elements are immutable):
(1, 2, 3) - Booleans:
True,False
❌ Not Allowed as Keys
- Lists:
[1, 2, 3] - Dictionaries:
{"a": 1} - Sets:
{1, 2, 3} - Any mutable object
Creating Dictionaries - 7 Different Ways
1. Direct Creation
Curly Brace Syntax
student = {"name": "Alice", "age": 21}
dict() Constructor
student = dict(name="Alice", age=21)
2. From Key-Value Pairs
List of Tuples
pairs = [("name", "Alice"), ("age", 21)]
student = dict(pairs)
Two Lists (zip)
keys = ["name", "age", "course"]
values = ["Alice", 21, "CS"]
student = dict(zip(keys, values))
3. Dictionary Comprehension
# Create squares dictionary
squares = {x: x**2 for x in range(1, 6)}
# {1: 1, 2: 4, 3: 9, 4: 16, 5: 25}
# With condition
even_squares = {x: x**2 for x in range(10) if x % 2 == 0}
# {0: 0, 2: 4, 4: 16, 6: 36, 8: 64}
4. fromkeys() Method
# All keys get same value
default_dict = dict.fromkeys(["a", "b", "c"], 0)
# {'a': 0, 'b': 0, 'c': 0}
# Without value (defaults to None)
keys = ["name", "age", "email"]
empty_dict = dict.fromkeys(keys)
# {'name': None, 'age': None, 'email': None}
5. Copying Dictionaries
original = {"a": 1, "b": 2}
# Shallow copy (references shared)
copy1 = original.copy()
# Using dict() constructor
copy2 = dict(original)
# Deep copy (for nested dicts)
import copy
deep_copy = copy.deepcopy(original)
Complete Dictionary Methods
| Method | Description | Time Complexity | Example & Output |
|---|---|---|---|
| get(key, default) | Safe access; returns default if key missing | O(1) | d.get("name", "Unknown") → "Alice" |
| setdefault(key, default) | Get value if exists, else set to default | O(1) | d.setdefault("grade", "A") → "A" |
| pop(key, default) | Remove key and return its value | O(1) | d.pop("age") → 21 |
| popitem() | Remove and return last (key, value) pair | O(1) | d.popitem() → ("course", "CS") |
| update(other_dict) | Merge another dictionary | O(n) | d.update({"grade": "A"}) |
| clear() | Remove all items | O(1) | d.clear() → {} |
| keys() | Return view of all keys | O(1) | list(d.keys()) → ["name", "age"] |
| values() | Return view of all values | O(1) | list(d.values()) → ["Alice", 21] |
| items() | Return view of (key, value) pairs | O(1) | list(d.items()) → [("name","Alice"),...] |
Practical Method Examples
Safe Access Patterns
config = {"theme": "dark", "language": "en"}
# ❌ Risky - raises KeyError
# value = config["font_size"]
# ✅ Safe with get()
value = config.get("font_size", "default")
# ✅ Safe with setdefault (creates if missing)
font = config.setdefault("font_size", 14)
print(config) # Adds 'font_size': 14 if missing
Iteration Techniques
student = {"name": "Alice", "age": 21, "course": "CS"}
# Loop through keys
for key in student:
print(key)
# Loop through key-value pairs
for key, value in student.items():
print(f"{key}: {value}")
# Loop through values
for value in student.values():
print(value)
Dictionary Operations & Functions
Common Operations
Membership Testing
student = {"name": "Alice", "age": 21}
# Check key existence
print("name" in student) # True
print("grade" not in student) # True
# Check value existence
print("Alice" in student.values()) # True
Merging Dictionaries
# Python 3.9+ Merge operator
dict1 = {"a": 1, "b": 2}
dict2 = {"b": 3, "c": 4}
merged = dict1 | dict2 # {'a': 1, 'b': 3, 'c': 4}
# Update in-place
dict1 |= dict2 # dict1 now has dict2's items
Built-in Functions
Utility Functions
inventory = {"apples": 10, "bananas": 5, "oranges": 8}
# Length
print(len(inventory)) # 3
# Sort by keys
sorted_keys = sorted(inventory) # ['apples', 'bananas', 'oranges']
# Sort by values
sorted_items = sorted(inventory.items(),
key=lambda x: x[1])
# [('bananas', 5), ('oranges', 8), ('apples', 10)]
# Any/All with dict
print(any(inventory)) # True (non-empty)
print(all(inventory)) # True (all keys truthy)
Dictionary Views
data = {"a": 1, "b": 2, "c": 3}
# Create views (dynamic)
keys_view = data.keys() # dict_keys(['a', 'b', 'c'])
values_view = data.values() # dict_values([1, 2, 3])
items_view = data.items() # dict_items([('a', 1), ...])
# Views update with dictionary
data["d"] = 4
print(list(keys_view)) # ['a', 'b', 'c', 'd']
Advanced Dictionary Concepts
Collections Module Utilities
defaultdict
from collections import defaultdict
# Auto-initialize missing keys
word_counts = defaultdict(int)
for word in ["apple", "banana", "apple"]:
word_counts[word] += 1
# defaultdict(, {'apple': 2, 'banana': 1})
# With list factory
groups = defaultdict(list)
groups["fruits"].append("apple") # No KeyError!
OrderedDict
from collections import OrderedDict
# Maintains insertion order (Python <3.7)
ordered = OrderedDict()
ordered["first"] = 1
ordered["second"] = 2
ordered["third"] = 3
# Move to end/beginning
ordered.move_to_end("first")
Counter
from collections import Counter
# Count frequencies
words = ["apple", "banana", "apple", "orange", "banana", "apple"]
counter = Counter(words)
print(counter.most_common(2))
# [('apple', 3), ('banana', 2)]
Performance & Memory
Hash Table Internals
Dictionaries use hash tables for O(1) average lookup time:
# Hash of key determines storage location
hash("name") # Returns integer hash value
# Collision resolution via open addressing
# Load factor triggers resizing (usually 2/3)
Memory Optimization
# 1. Use __slots__ for many similar objects
class Student:
__slots__ = ["name", "age"] # Saves memory
# 2. Consider arrays for numeric data
import array
nums = array.array('i', [1, 2, 3]) # More compact
# 3. Use tuples for immutable data
coordinates = (10, 20) # Less overhead than dict
Performance Tips
key in dictis O(1) average case- Avoid using mutable objects as keys
- Prefer
dict.get()over try-except for missing keys - Use dictionary comprehensions for creation
Real-World Applications
Configuration Management
# App configuration
config = {
"database": {
"host": "localhost",
"port": 5432,
"user": "admin"
},
"server": {
"port": 8000,
"debug": True
},
"features": ["auth", "logging", "cache"]
}
# Access nested config
db_host = config["database"]["host"]
Data Aggregation
# Sales data aggregation
sales = [
{"product": "Apple", "amount": 100},
{"product": "Banana", "amount": 150},
{"product": "Apple", "amount": 200}
]
# Aggregate by product
totals = {}
for sale in sales:
product = sale["product"]
totals[product] = totals.get(product, 0) + sale["amount"]
# {'Apple': 300, 'Banana': 150}
Function Dispatch Table
# Command pattern implementation
def add(x, y):
return x + y
def multiply(x, y):
return x * y
def power(x, y):
return x ** y
# Dispatch table
operations = {
"add": add,
"multiply": multiply,
"power": power
}
# Execute dynamically
result = operations["add"](10, 5) # 15
Practical Example: Inventory System
Complete Implementation
class InventorySystem:
def __init__(self):
self.products = {}
self.categories = defaultdict(list)
def add_product(self, id, name, price, category):
self.products[id] = {
"name": name,
"price": price,
"category": category,
"stock": 0
}
self.categories[category].append(id)
def update_stock(self, id, quantity):
if id in self.products:
self.products[id]["stock"] += quantity
def get_products_by_category(self, category):
return {
pid: self.products[pid]
for pid in self.categories.get(category, [])
}
def __str__(self):
return f"Inventory with {len(self.products)} products"
# Usage
inventory = InventorySystem()
inventory.add_product("P001", "Laptop", 999.99, "Electronics")
inventory.update_stock("P001", 10)
JSON Serialization
import json
# Dictionary to JSON
data = {
"name": "Alice",
"age": 21,
"courses": ["Math", "CS"],
"graduated": False
}
# Serialize
json_str = json.dumps(data, indent=2)
print(json_str)
# Deserialize
parsed = json.loads(json_str)
print(parsed["name"]) # Alice
# Working with JSON files
with open("data.json", "w") as f:
json.dump(data, f)
with open("data.json", "r") as f:
loaded = json.load(f)
Learning Resources & Training
Official Python Docs
Complete reference for dictionaries and data structures
Real Python Tutorial
In-depth tutorials with practical examples
GeeksforGeeks Guide
Comprehensive guide with coding problems
Python Training at ZN Infotech
What We Offer
- Core Python & Advanced Concepts
- Data Structures & Algorithms
- Web Development with Django/Flask
- Data Science & Machine Learning
- Industrial Training & Internships
Contact Information
+91 9335726249
info@zninfotech.com
1st Floor, Super Complex, Kursi Road, Tedhi Pulia, Lucknow-226020
Visit Our WebsitePractice Exercises
Beginner Exercises
1. Create and Access
Create a dictionary for a book with title, author, year, and price. Access each value.
# Your solution here
2. Frequency Counter
Count the frequency of each character in "hello world".
3. Merge Dictionaries
Merge two dictionaries, handling duplicate keys by summing values.
Advanced Exercises
4. Invert Dictionary
Create a function that inverts a dictionary (keys become values). Handle duplicate values.
5. Nested Dictionary Flattening
Flatten a nested dictionary, creating keys like "user.name" for nested values.
6. LRU Cache Implementation
Implement a Least Recently Used cache using OrderedDict with size limit.