Collections Module
Learning Objectives
- By the end of this lesson, you will be able to:
- - Use `namedtuple` for creating tuple subclasses with named fields
- - Use `deque` for efficient double-ended queues
- - Use `Counter` for counting hashable objects
- - Use `defaultdict` for dictionaries with default values
- - Use `OrderedDict` for ordered dictionaries
- - Understand when to use each collection type
- - Apply collections in practical scenarios
- - Choose appropriate collection for your needs
Lesson 12.1: Collections Module
Learning Objectives
By the end of this lesson, you will be able to:
- Use
namedtuplefor creating tuple subclasses with named fields - Use
dequefor efficient double-ended queues - Use
Counterfor counting hashable objects - Use
defaultdictfor dictionaries with default values - Use
OrderedDictfor ordered dictionaries - Understand when to use each collection type
- Apply collections in practical scenarios
- Choose appropriate collection for your needs
Introduction to Collections Module
The collections module provides specialized container datatypes that are alternatives to Python's general-purpose built-in containers (dict, list, set, tuple).
Why Collections?
- Performance: Optimized for specific use cases
- Functionality: Provide additional features
- Convenience: Simplify common operations
- Memory efficiency: More efficient for specific patterns
Collections Overview
- namedtuple: Tuple with named fields
- deque: Double-ended queue
- Counter: Count hashable objects
- defaultdict: Dictionary with default factory
- OrderedDict: Dictionary that remembers insertion order
namedtuple
namedtuple creates tuple subclasses with named fields, making code more readable and self-documenting.
Creating namedtuple
from collections import namedtuple
# Define namedtuple type
Point = namedtuple('Point', ['x', 'y'])
# Create instances
p1 = Point(3, 4)
p2 = Point(x=5, y=6)
print(p1.x, p1.y) # 3 4
print(p2.x, p2.y) # 5 6
Accessing Fields
from collections import namedtuple
Person = namedtuple('Person', ['name', 'age', 'city'])
person = Person('Alice', 30, 'New York')
# Access by name
print(person.name) # Alice
print(person.age) # 30
print(person.city) # New York
# Access by index (still works)
print(person[0]) # Alice
print(person[1]) # 30
print(person[2]) # New York
namedtuple Methods
from collections import namedtuple
Point = namedtuple('Point', ['x', 'y'])
p = Point(3, 4)
# Convert to dictionary
print(p._asdict()) # OrderedDict([('x', 3), ('y', 4)])
# Replace fields (creates new instance)
p2 = p._replace(x=10)
print(p2) # Point(x=10, y=4)
# Get field names
print(p._fields) # ('x', 'y')
Practical Example: Coordinates
from collections import namedtuple
# Define coordinate
Coordinate = namedtuple('Coordinate', ['latitude', 'longitude'])
# Create coordinates
nyc = Coordinate(40.7128, -74.0060)
london = Coordinate(51.5074, -0.1278)
print(f"NYC: {nyc.latitude}, {nyc.longitude}")
print(f"London: {london.latitude}, {london.longitude}")
Practical Example: Data Records
from collections import namedtuple
# Define record structure
Student = namedtuple('Student', ['name', 'age', 'grades'])
students = [
Student('Alice', 20, [85, 90, 88]),
Student('Bob', 19, [92, 87, 90]),
Student('Charlie', 21, [78, 85, 82])
]
for student in students:
avg = sum(student.grades) / len(student.grades)
print(f"{student.name}: {avg:.2f}")
deque
deque (double-ended queue) is a list-like container optimized for fast appends and pops from both ends.
Creating deque
from collections import deque
# Create deque
dq = deque([1, 2, 3])
print(dq) # deque([1, 2, 3])
# Create empty deque
dq = deque()
dq.append(1)
dq.append(2)
Adding Elements
from collections import deque
dq = deque([1, 2, 3])
# Add to right (end)
dq.append(4)
print(dq) # deque([1, 2, 3, 4])
# Add to left (beginning)
dq.appendleft(0)
print(dq) # deque([0, 1, 2, 3, 4])
# Extend from right
dq.extend([5, 6])
print(dq) # deque([0, 1, 2, 3, 4, 5, 6])
# Extend from left
dq.extendleft([-2, -1])
print(dq) # deque([-1, -2, 0, 1, 2, 3, 4, 5, 6])
Removing Elements
from collections import deque
dq = deque([1, 2, 3, 4, 5])
# Remove from right
value = dq.pop()
print(value) # 5
print(dq) # deque([1, 2, 3, 4])
# Remove from left
value = dq.popleft()
print(value) # 1
print(dq) # deque([2, 3, 4])
deque Operations
from collections import deque
dq = deque([1, 2, 3, 4, 5])
# Rotate
dq.rotate(2) # Rotate right
print(dq) # deque([4, 5, 1, 2, 3])
dq.rotate(-1) # Rotate left
print(dq) # deque([5, 1, 2, 3, 4])
# Maximum size
dq_max = deque([1, 2, 3], maxlen=5)
dq_max.append(4)
dq_max.append(5)
dq_max.append(6) # Removes leftmost (1)
print(dq_max) # deque([2, 3, 4, 5, 6], maxlen=5)
Practical Example: Queue
from collections import deque
# Use deque as queue (FIFO)
queue = deque()
# Enqueue
queue.append('task1')
queue.append('task2')
queue.append('task3')
# Dequeue
while queue:
task = queue.popleft()
print(f"Processing: {task}")
Practical Example: Stack
from collections import deque
# Use deque as stack (LIFO)
stack = deque()
# Push
stack.append('item1')
stack.append('item2')
stack.append('item3')
# Pop
while stack:
item = stack.pop()
print(f"Popped: {item}")
Counter
Counter is a dict subclass for counting hashable objects.
Creating Counter
from collections import Counter
# From iterable
words = ['apple', 'banana', 'apple', 'cherry', 'banana', 'apple']
counter = Counter(words)
print(counter) # Counter({'apple': 3, 'banana': 2, 'cherry': 1})
# From string
text = "hello world"
char_counter = Counter(text)
print(char_counter)
# From dictionary
counter = Counter({'a': 3, 'b': 2, 'c': 1})
Counter Operations
from collections import Counter
c1 = Counter(['a', 'b', 'c', 'a'])
c2 = Counter(['a', 'b', 'b'])
# Addition
print(c1 + c2) # Counter({'a': 3, 'b': 3, 'c': 1})
# Subtraction
print(c1 - c2) # Counter({'a': 1, 'c': 1})
# Union (max)
print(c1 | c2) # Counter({'a': 2, 'b': 2, 'c': 1})
# Intersection (min)
print(c1 & c2) # Counter({'a': 1, 'b': 1})
Counter Methods
from collections import Counter
counter = Counter(['a', 'b', 'c', 'a', 'b', 'a'])
# Most common
print(counter.most_common(2)) # [('a', 3), ('b', 2)]
# Elements (iterator)
print(list(counter.elements())) # ['a', 'a', 'a', 'b', 'b', 'c']
# Subtract
counter.subtract(['a', 'b'])
print(counter) # Counter({'a': 2, 'b': 1, 'c': 1})
# Update
counter.update(['a', 'b', 'c'])
print(counter) # Counter({'a': 3, 'b': 2, 'c': 2})
Practical Example: Word Frequency
from collections import Counter
def word_frequency(text):
"""Count word frequency in text."""
words = text.lower().split()
return Counter(words)
text = "the quick brown fox jumps over the lazy dog the fox"
freq = word_frequency(text)
print(freq.most_common(3)) # [('the', 3), ('fox', 2), ...]
Practical Example: Character Frequency
from collections import Counter
def char_frequency(text):
"""Count character frequency."""
return Counter(text.lower())
text = "Hello World"
char_freq = char_frequency(text)
print(char_freq.most_common(5))
defaultdict
defaultdict is a dictionary subclass that calls a factory function to supply missing values.
Creating defaultdict
from collections import defaultdict
# defaultdict with list factory
dd_list = defaultdict(list)
dd_list['fruits'].append('apple')
dd_list['fruits'].append('banana')
print(dd_list) # defaultdict(<class 'list'>, {'fruits': ['apple', 'banana']})
# defaultdict with int factory
dd_int = defaultdict(int)
dd_int['count'] += 1
dd_int['count'] += 1
print(dd_int['count']) # 2
defaultdict with Different Factories
from collections import defaultdict
# List factory
dd_list = defaultdict(list)
dd_list['items'].append(1)
# Int factory
dd_int = defaultdict(int)
dd_int['counter'] += 1
# Set factory
dd_set = defaultdict(set)
dd_set['tags'].add('python')
# String factory
dd_str = defaultdict(str)
dd_str['name'] += 'Hello'
# Custom factory function
def default_factory():
return "default value"
dd_custom = defaultdict(default_factory)
print(dd_custom['key']) # 'default value'
Practical Example: Grouping
from collections import defaultdict
# Group items by category
items = [
('fruit', 'apple'),
('fruit', 'banana'),
('vegetable', 'carrot'),
('fruit', 'cherry'),
('vegetable', 'potato')
]
grouped = defaultdict(list)
for category, item in items:
grouped[category].append(item)
print(dict(grouped))
# {'fruit': ['apple', 'banana', 'cherry'], 'vegetable': ['carrot', 'potato']}
Practical Example: Counting
from collections import defaultdict
# Count items
items = ['apple', 'banana', 'apple', 'cherry', 'banana', 'apple']
count = defaultdict(int)
for item in items:
count[item] += 1
print(dict(count)) # {'apple': 3, 'banana': 2, 'cherry': 1}
OrderedDict
OrderedDict is a dictionary subclass that remembers the order entries were added.
Creating OrderedDict
from collections import OrderedDict
# Create ordered dict
od = OrderedDict()
od['first'] = 1
od['second'] = 2
od['third'] = 3
print(od) # OrderedDict([('first', 1), ('second', 2), ('third', 3)])
OrderedDict Operations
from collections import OrderedDict
od = OrderedDict([('a', 1), ('b', 2), ('c', 3)])
# Move to end
od.move_to_end('a')
print(od) # OrderedDict([('b', 2), ('c', 3), ('a', 1)])
# Move to beginning
od.move_to_end('a', last=False)
print(od) # OrderedDict([('a', 1), ('b', 2), ('c', 3)])
# Pop last
last = od.popitem()
print(last) # ('c', 3)
# Pop first
first = od.popitem(last=False)
print(first) # ('a', 1)
Note: Python 3.7+ Dicts are Ordered
In Python 3.7+, regular dictionaries remember insertion order, so OrderedDict is less necessary but still useful for:
- Explicit ordering requirements
move_to_end()method- Equality based on order
- Backward compatibility
# Python 3.7+: Regular dict maintains order
d = {'first': 1, 'second': 2, 'third': 3}
print(d) # {'first': 1, 'second': 2, 'third': 3} (ordered)
# But OrderedDict still useful for move_to_end()
from collections import OrderedDict
od = OrderedDict([('a', 1), ('b', 2), ('c', 3)])
od.move_to_end('a') # Only available in OrderedDict
Practical Example: LRU Cache (Concept)
from collections import OrderedDict
class LRUCache:
def __init__(self, capacity):
self.cache = OrderedDict()
self.capacity = capacity
def get(self, key):
if key not in self.cache:
return -1
self.cache.move_to_end(key)
return self.cache[key]
def put(self, key, value):
if key in self.cache:
self.cache.move_to_end(key)
self.cache[key] = value
if len(self.cache) > self.capacity:
self.cache.popitem(last=False)
Practical Examples
Example 1: Data Processing with namedtuple
from collections import namedtuple
# Define data structure
Transaction = namedtuple('Transaction', ['date', 'amount', 'type'])
transactions = [
Transaction('2024-01-01', 100, 'income'),
Transaction('2024-01-02', -50, 'expense'),
Transaction('2024-01-03', 200, 'income'),
]
total_income = sum(t.amount for t in transactions if t.type == 'income')
total_expense = sum(t.amount for t in transactions if t.type == 'expense')
print(f"Income: ${total_income}")
print(f"Expense: ${total_expense}")
Example 2: Sliding Window with deque
from collections import deque
def sliding_window_max(nums, k):
"""Find maximum in each sliding window."""
result = []
window = deque()
for i, num in enumerate(nums):
# Remove indices outside window
while window and window[0] <= i - k:
window.popleft()
# Remove indices with smaller values
while window and nums[window[-1]] < num:
window.pop()
window.append(i)
# Add maximum if window is full
if i >= k - 1:
result.append(nums[window[0]])
return result
nums = [1, 3, -1, -3, 5, 3, 6, 7]
print(sliding_window_max(nums, 3)) # [3, 3, 5, 5, 6, 7]
Example 3: Text Analysis with Counter
from collections import Counter
import re
def analyze_text(text):
"""Analyze text statistics."""
# Word frequency
words = re.findall(r'\w+', text.lower())
word_freq = Counter(words)
# Character frequency
char_freq = Counter(text.lower())
return {
'word_frequency': word_freq.most_common(10),
'character_frequency': char_freq.most_common(10),
'total_words': len(words),
'unique_words': len(word_freq)
}
text = "The quick brown fox jumps over the lazy dog. The fox is quick."
stats = analyze_text(text)
print(stats)
Best Practices
1. Choose Appropriate Collection
# Use namedtuple for structured data
Point = namedtuple('Point', ['x', 'y'])
# Use deque for queues/stacks
queue = deque()
# Use Counter for counting
counter = Counter(items)
# Use defaultdict for grouping
grouped = defaultdict(list)
2. Use namedtuple for Readability
# Good: Clear field names
Person = namedtuple('Person', ['name', 'age'])
person = Person('Alice', 30)
# Avoid: Unclear tuple
person = ('Alice', 30) # What is index 0? 1?
3. Use defaultdict to Avoid KeyError
# Good: No KeyError
dd = defaultdict(list)
dd['key'].append('value')
# Avoid: Need to check key
d = {}
if 'key' not in d:
d['key'] = []
d['key'].append('value')
Common Mistakes and Pitfalls
1. Forgetting namedtuple is Immutable
from collections import namedtuple
Point = namedtuple('Point', ['x', 'y'])
p = Point(3, 4)
# WRONG: Cannot modify
# p.x = 5 # AttributeError
# CORRECT: Create new instance
p = p._replace(x=5)
2. Using deque When List is Fine
# WRONG: deque for simple list operations
dq = deque()
dq.append(1)
dq.append(2)
value = dq[0] # Works but list is simpler
# CORRECT: Use list for simple operations
lst = [1, 2]
value = lst[0]
3. Not Using Counter When Counting
# WRONG: Manual counting
count = {}
for item in items:
if item not in count:
count[item] = 0
count[item] += 1
# CORRECT: Use Counter
from collections import Counter
count = Counter(items)
Practice Exercise
Exercise: Collections
Objective: Create a Python program that demonstrates using collections module.
Instructions:
-
Create a file called
collections_practice.py -
Write a program that:
- Uses namedtuple
- Uses deque
- Uses Counter
- Uses defaultdict
- Uses OrderedDict
- Demonstrates practical applications
-
Your program should include:
- Creating and using each collection type
- Common operations
- Practical examples
Example Solution:
"""
Collections Module Practice
This program demonstrates using collections module.
"""
from collections import namedtuple, deque, Counter, defaultdict, OrderedDict
print("=" * 60)
print("COLLECTIONS MODULE PRACTICE")
print("=" * 60)
print()
# 1. namedtuple - Creating and using
print("1. NAMEDTUPLE - CREATING AND USING")
print("-" * 60)
Point = namedtuple('Point', ['x', 'y'])
p1 = Point(3, 4)
p2 = Point(x=5, y=6)
print(f"Point 1: x={p1.x}, y={p1.y}")
print(f"Point 2: x={p2.x}, y={p2.y}")
print(f"Point 1 as dict: {p1._asdict()}")
print()
# 2. namedtuple - Methods
print("2. NAMEDTUPLE - METHODS")
print("-" * 60)
Person = namedtuple('Person', ['name', 'age', 'city'])
person = Person('Alice', 30, 'New York')
print(f"Person: {person}")
print(f"Field names: {person._fields}")
person_updated = person._replace(age=31)
print(f"Updated person: {person_updated}")
print()
# 3. namedtuple - Data records
print("3. NAMEDTUPLE - DATA RECORDS")
print("-" * 60)
Student = namedtuple('Student', ['name', 'age', 'grades'])
students = [
Student('Alice', 20, [85, 90, 88]),
Student('Bob', 19, [92, 87, 90]),
Student('Charlie', 21, [78, 85, 82])
]
for student in students:
avg = sum(student.grades) / len(student.grades)
print(f"{student.name}: average={avg:.2f}")
print()
# 4. deque - Creating and adding
print("4. DEQUE - CREATING AND ADDING")
print("-" * 60)
dq = deque([1, 2, 3])
print(f"Initial: {dq}")
dq.append(4) # Add to right
dq.appendleft(0) # Add to left
print(f"After append: {dq}")
dq.extend([5, 6]) # Extend right
dq.extendleft([-2, -1]) # Extend left
print(f"After extend: {dq}")
print()
# 5. deque - Removing elements
print("5. DEQUE - REMOVING ELEMENTS")
print("-" * 60)
dq = deque([1, 2, 3, 4, 5])
print(f"Initial: {dq}")
right = dq.pop()
left = dq.popleft()
print(f"Popped right: {right}, left: {left}")
print(f"After pop: {dq}")
print()
# 6. deque - Rotate
print("6. DEQUE - ROTATE")
print("-" * 60)
dq = deque([1, 2, 3, 4, 5])
print(f"Initial: {dq}")
dq.rotate(2)
print(f"Rotate right 2: {dq}")
dq.rotate(-1)
print(f"Rotate left 1: {dq}")
print()
# 7. deque - Max length
print("7. DEQUE - MAX LENGTH")
print("-" * 60)
dq = deque([1, 2, 3], maxlen=5)
dq.extend([4, 5, 6])
print(f"With maxlen=5: {dq}")
print()
# 8. deque - Queue (FIFO)
print("8. DEQUE - QUEUE (FIFO)")
print("-" * 60)
queue = deque()
queue.append('task1')
queue.append('task2')
queue.append('task3')
print("Processing queue:")
while queue:
task = queue.popleft()
print(f" Processing: {task}")
print()
# 9. deque - Stack (LIFO)
print("9. DEQUE - STACK (LIFO)")
print("-" * 60)
stack = deque()
stack.append('item1')
stack.append('item2')
stack.append('item3')
print("Popping stack:")
while stack:
item = stack.pop()
print(f" Popped: {item}")
print()
# 10. Counter - Creating
print("10. COUNTER - CREATING")
print("-" * 60)
words = ['apple', 'banana', 'apple', 'cherry', 'banana', 'apple']
counter = Counter(words)
print(f"Word counter: {counter}")
text = "hello world"
char_counter = Counter(text)
print(f"Character counter: {char_counter.most_common(5)}")
print()
# 11. Counter - Operations
print("11. COUNTER - OPERATIONS")
print("-" * 60)
c1 = Counter(['a', 'b', 'c', 'a'])
c2 = Counter(['a', 'b', 'b'])
print(f"c1: {c1}")
print(f"c2: {c2}")
print(f"c1 + c2: {c1 + c2}")
print(f"c1 - c2: {c1 - c2}")
print()
# 12. Counter - Methods
print("12. COUNTER - METHODS")
print("-" * 60)
counter = Counter(['a', 'b', 'c', 'a', 'b', 'a'])
print(f"Counter: {counter}")
print(f"Most common 2: {counter.most_common(2)}")
print(f"Elements: {list(counter.elements())}")
print()
# 13. Counter - Update and subtract
print("13. COUNTER - UPDATE AND SUBTRACT")
print("-" * 60)
counter = Counter(['a', 'b', 'c'])
print(f"Initial: {counter}")
counter.update(['a', 'b'])
print(f"After update: {counter}")
counter.subtract(['a'])
print(f"After subtract: {counter}")
print()
# 14. defaultdict - List factory
print("14. DEFAULTDICT - LIST FACTORY")
print("-" * 60)
dd_list = defaultdict(list)
dd_list['fruits'].append('apple')
dd_list['fruits'].append('banana')
dd_list['vegetables'].append('carrot')
print(f"Defaultdict list: {dict(dd_list)}")
print()
# 15. defaultdict - Int factory
print("15. DEFAULTDICT - INT FACTORY")
print("-" * 60)
dd_int = defaultdict(int)
dd_int['count'] += 1
dd_int['count'] += 1
dd_int['other'] += 1
print(f"Defaultdict int: {dict(dd_int)}")
print()
# 16. defaultdict - Set factory
print("16. DEFAULTDICT - SET FACTORY")
print("-" * 60)
dd_set = defaultdict(set)
dd_set['tags'].add('python')
dd_set['tags'].add('programming')
dd_set['tags'].add('python') # Duplicate ignored
print(f"Defaultdict set: {dict(dd_set)}")
print()
# 17. defaultdict - Grouping
print("17. DEFAULTDICT - GROUPING")
print("-" * 60)
items = [
('fruit', 'apple'),
('fruit', 'banana'),
('vegetable', 'carrot'),
('fruit', 'cherry'),
]
grouped = defaultdict(list)
for category, item in items:
grouped[category].append(item)
print(f"Grouped items: {dict(grouped)}")
print()
# 18. defaultdict - Counting
print("18. DEFAULTDICT - COUNTING")
print("-" * 60)
items = ['apple', 'banana', 'apple', 'cherry', 'banana', 'apple']
count = defaultdict(int)
for item in items:
count[item] += 1
print(f"Count: {dict(count)}")
print()
# 19. OrderedDict - Creating and operations
print("19. ORDEREDDICT - CREATING AND OPERATIONS")
print("-" * 60)
od = OrderedDict([('a', 1), ('b', 2), ('c', 3)])
print(f"Initial: {od}")
od.move_to_end('a')
print(f"After move_to_end('a'): {od}")
od.move_to_end('a', last=False)
print(f"After move_to_end('a', last=False): {od}")
print()
# 20. OrderedDict - Pop operations
print("20. ORDEREDDICT - POP OPERATIONS")
print("-" * 60)
od = OrderedDict([('a', 1), ('b', 2), ('c', 3)])
print(f"Initial: {od}")
last = od.popitem()
print(f"Pop last: {last}, remaining: {od}")
first = od.popitem(last=False)
print(f"Pop first: {first}, remaining: {od}")
print()
# 21. Practical: Word frequency analysis
print("21. PRACTICAL: WORD FREQUENCY ANALYSIS")
print("-" * 60)
text = "the quick brown fox jumps over the lazy dog the fox"
words = text.split()
word_freq = Counter(words)
print(f"Word frequencies: {word_freq.most_common(3)}")
print()
# 22. Practical: Grouping data
print("22. PRACTICAL: GROUPING DATA")
print("-" * 60)
transactions = [
('income', 100),
('expense', 50),
('income', 200),
('expense', 30),
('income', 150),
]
grouped = defaultdict(list)
for category, amount in transactions:
grouped[category].append(amount)
for category, amounts in grouped.items():
total = sum(amounts)
print(f"{category}: {amounts} (total: {total})")
print()
# 23. Practical: Queue implementation
print("23. PRACTICAL: QUEUE IMPLEMENTATION")
print("-" * 60)
queue = deque(['task1', 'task2', 'task3'])
print(f"Queue: {queue}")
# Process queue
while queue:
task = queue.popleft()
print(f"Processing: {task}")
print()
# 24. Practical: Named records
print("24. PRACTICAL: NAMED RECORDS")
print("-" * 60)
Transaction = namedtuple('Transaction', ['date', 'amount', 'type'])
transactions = [
Transaction('2024-01-01', 100, 'income'),
Transaction('2024-01-02', -50, 'expense'),
Transaction('2024-01-03', 200, 'income'),
]
total = sum(t.amount for t in transactions)
print(f"Total transactions: {len(transactions)}")
print(f"Net amount: ${total}")
print()
print("=" * 60)
print("PRACTICE COMPLETE!")
print("=" * 60)
Expected Output (truncated):
============================================================
COLLECTIONS MODULE PRACTICE
============================================================
1. NAMEDTUPLE - CREATING AND USING
------------------------------------------------------------
Point 1: x=3, y=4
Point 2: x=5, y=6
Point 1 as dict: OrderedDict([('x', 3), ('y', 4)])
[... rest of output ...]
Challenge (Optional):
- Implement an LRU cache using OrderedDict
- Build a sliding window algorithm using deque
- Create a data analysis tool using Counter
- Build a grouping utility using defaultdict
Key Takeaways
- namedtuple creates tuple subclasses with named fields
- deque is a double-ended queue optimized for both ends
- Counter counts hashable objects efficiently
- defaultdict provides default values for missing keys
- OrderedDict maintains insertion order (Python 3.7+ dicts also ordered)
- Use namedtuple for structured, immutable data
- Use deque for queues and stacks (faster than list for ends)
- Use Counter for counting operations (simpler than manual counting)
- Use defaultdict to avoid KeyError and simplify grouping
- Collections provide optimized alternatives to built-in types
- namedtuple is immutable - use
_replace()to create new instances - deque supports rotate() and maxlen for specialized use cases
- Counter supports arithmetic operations (+, -, |, &)
- defaultdict factory can be list, int, set, or custom function
- OrderedDict still useful for move_to_end() and explicit ordering
Quiz: Collections
Test your understanding with these questions:
-
What does namedtuple create?
- A) Named dictionary
- B) Tuple subclass with named fields
- C) Named list
- D) Named set
-
What is deque optimized for?
- A) Random access
- B) Operations on both ends
- C) Sorting
- D) Searching
-
What does Counter count?
- A) Only numbers
- B) Hashable objects
- C) Only strings
- D) Only lists
-
What does defaultdict provide?
- A) Sorted keys
- B) Default values for missing keys
- C) Fixed size
- D) Read-only access
-
What is OrderedDict?
- A) Dictionary sorted by key
- B) Dictionary that remembers insertion order
- C) Dictionary sorted by value
- D) Dictionary with unique values
-
Can you modify a namedtuple?
- A) Yes, directly
- B) No, it's immutable
- C) Only in Python 2
- D) Only with special method
-
What does deque.rotate() do?
- A) Sorts elements
- B) Rotates elements
- C) Reverses elements
- D) Shuffles elements
-
What does Counter.most_common() return?
- A) Least common items
- B) Most common items
- C) All items
- D) Unique items
-
What factory is commonly used with defaultdict?
- A) dict
- B) tuple
- C) list or int
- D) set
-
When should you use collections?
- A) Never
- B) When built-in types are insufficient
- C) Always
- D) Only for large data
Answers:
- B) Tuple subclass with named fields (namedtuple definition)
- B) Operations on both ends (deque optimization)
- B) Hashable objects (Counter counts hashable items)
- B) Default values for missing keys (defaultdict feature)
- B) Dictionary that remembers insertion order (OrderedDict definition)
- B) No, it's immutable (must use _replace() for new instance)
- B) Rotates elements (rotate method rotates deque)
- B) Most common items (most_common returns most frequent)
- C) list or int (common factories for defaultdict)
- B) When built-in types are insufficient (use when appropriate)
Next Steps
Excellent work! You've mastered the collections module. You now understand:
- How to use namedtuple, deque, Counter, defaultdict, OrderedDict
- When to use each collection type
- Practical applications
What's Next?
- Lesson 12.2: Generators and Iterators
- Learn about generator functions
- Understand iterator protocol
- Explore generator expressions
Additional Resources
- collections: docs.python.org/3/library/collections.html
- namedtuple: docs.python.org/3/library/collections.html#collections.namedtuple
- deque: docs.python.org/3/library/collections.html#collections.deque
Lesson completed! You're ready to move on to the next lesson.