Python Programming Labs

Master Python's powerful standard library modules: itertools, functools, and collections.

Python Standard Library Mastery - Module 8

Unlock the full power of Python's built-in modules for efficient programming.

Lab 22: Itertools Module
Expert
Coding Challenge
Your Task: Learn to use itertools for efficient iteration and combinatorics with lazy evaluation.

Detailed Requirements:
1. Infinite iterators:
from itertools import count, cycle, repeat # count(start, step) - infinite counter for i in count(10, 2): if i > 20: break print(i) # 10, 12, 14, 16, 18, 20 # cycle(iterable) - infinite cycling colors = cycle(['red', 'green', 'blue']) for _ in range(5): print(next(colors)) # repeat(elem, n) - repeat element list(repeat('A', 3)) # ['A', 'A', 'A']

2. Combinatoric iterators:
from itertools import permutations, combinations, product # All arrangements list(permutations('ABC', 2)) # [('A','B'), ('A','C'), ('B','A'), ('B','C'), ('C','A'), ('C','B')] # All combinations (no repetition) list(combinations('ABC', 2)) # [('A','B'), ('A','C'), ('B','C')] # Cartesian product list(product('AB', '12')) # [('A','1'), ('A','2'), ('B','1'), ('B','2')]

3. Terminating iterators:
from itertools import chain, islice, groupby, takewhile # Chain multiple iterables list(chain([1,2], [3,4])) # [1, 2, 3, 4] # Slice an iterator list(islice(count(), 5)) # [0, 1, 2, 3, 4] # Group consecutive elements data = [('a', 1), ('a', 2), ('b', 3)] for key, group in groupby(data, lambda x: x[0]): print(key, list(group))

4. Accumulate and starmap:
from itertools import accumulate, starmap import operator # Running totals list(accumulate([1, 2, 3, 4])) # [1, 3, 6, 10] # With custom function list(accumulate([1,2,3,4], operator.mul)) # [1,2,6,24] # Apply function to unpacked args list(starmap(pow, [(2,3), (3,2)])) # [8, 9]

💡 Pro Tips:
• Itertools are memory-efficient (lazy evaluation)
• Use list() to materialize iterators
• combinations_with_replacement allows repeats
• Chain is great for flattening nested lists

Expected Output:
Permutations: [('A', 'B'), ('A', 'C'), ('B', 'A'), ...] Combinations: [('A', 'B'), ('A', 'C'), ('B', 'C')] Accumulated: [1, 3, 6, 10, 15]

Requirements Checklist

Import from itertools module
Use permutations or combinations
Use chain to combine iterables
Use accumulate for running totals
Use islice or takewhile
Print or use the results
Output
# Click "Run Code" to execute your Python code
Hints & Tips
• Import: from itertools import permutations, combinations
• Permutations: permutations('ABC', 2) - order matters
• Combinations: combinations('ABC', 2) - order doesn't matter
• Chain: chain(list1, list2) - combine iterables
• Accumulate: accumulate([1,2,3]) - running totals
Progress: 0/6
Score: 0/100
0%

Lab Results

Review feedback below

Lab 23: Functools Module
Expert
Coding Challenge
Your Task: Master functools for higher-order functions, caching, and function manipulation.

Detailed Requirements:
1. lru_cache for memoization:
from functools import lru_cache @lru_cache(maxsize=128) def fibonacci(n): if n < 2: return n return fibonacci(n-1) + fibonacci(n-2) print(fibonacci(100)) # Instant with caching! print(fibonacci.cache_info()) # Cache statistics

2. reduce for aggregation:
from functools import reduce # Sum of list total = reduce(lambda x, y: x + y, [1, 2, 3, 4, 5]) print(total) # 15 # Find maximum maximum = reduce(lambda x, y: x if x > y else y, [3, 1, 4, 1, 5]) print(maximum) # 5 # With initial value product = reduce(lambda x, y: x * y, [1, 2, 3, 4], 10) print(product) # 240 (10 * 1 * 2 * 3 * 4)

3. partial for function binding:
from functools import partial def power(base, exponent): return base ** exponent # Create specialized functions square = partial(power, exponent=2) cube = partial(power, exponent=3) print(square(5)) # 25 print(cube(3)) # 27 # Partial with multiple args def greet(greeting, name, punctuation): return f"{greeting}, {name}{punctuation}" say_hello = partial(greet, "Hello", punctuation="!") print(say_hello("Alice")) # Hello, Alice!

4. wraps for decorator metadata:
from functools import wraps def my_decorator(func): @wraps(func) # Preserves __name__, __doc__ def wrapper(*args, **kwargs): print("Before call") result = func(*args, **kwargs) print("After call") return result return wrapper @my_decorator def say_hello(): """Says hello""" print("Hello!") print(say_hello.__name__) # 'say_hello' (not 'wrapper') print(say_hello.__doc__) # 'Says hello'

💡 Pro Tips:
• @lru_cache dramatically speeds up recursive functions
• reduce is great for folding/aggregating sequences
• partial creates specialized versions of functions
• Always use @wraps in decorators

Expected Output:
Fibonacci(30): 832040 Sum: 15 Square of 5: 25

Requirements Checklist

Import from functools module
Use @lru_cache decorator
Use reduce function
Use partial for function binding
Use @wraps in a decorator
Print results to verify
Output
# Click "Run Code" to execute your Python code
Hints & Tips
• Import: from functools import lru_cache, reduce, partial
• Cache: @lru_cache(maxsize=128) above function
• Reduce: reduce(lambda x, y: x + y, [1,2,3])
• Partial: square = partial(power, exponent=2)
• Wraps: @wraps(func) inside decorator
Progress: 0/6
Score: 0/100
0%

Lab Results

Review feedback below

Lab 24: Collections Module
Expert
Coding Challenge
Your Task: Master specialized container datatypes from the collections module for efficient data handling.

Detailed Requirements:
1. Counter for counting:
from collections import Counter # Count occurrences words = ['apple', 'banana', 'apple', 'cherry', 'banana', 'apple'] counter = Counter(words) print(counter) # Counter({'apple': 3, 'banana': 2, 'cherry': 1}) print(counter.most_common(2)) # [('apple', 3), ('banana', 2)] counter.update(['apple', 'date']) # Add more print(counter['apple']) # 4

2. defaultdict for default values:
from collections import defaultdict # List as default groups = defaultdict(list) for item in [('a', 1), ('b', 2), ('a', 3)]: groups[item[0]].append(item[1]) print(dict(groups)) # {'a': [1, 3], 'b': [2]} # Int as default (counting) counts = defaultdict(int) for char in 'mississippi': counts[char] += 1 print(dict(counts)) # {'m': 1, 'i': 4, 's': 4, 'p': 2}

3. namedtuple for structured data:
from collections import namedtuple # Define a named tuple Point = namedtuple('Point', ['x', 'y']) p = Point(3, 4) print(p.x, p.y) # 3 4 print(p[0], p[1]) # 3 4 (also indexable) # With defaults (Python 3.7+) Person = namedtuple('Person', ['name', 'age', 'city'], defaults=['Unknown']) alice = Person('Alice', 30) print(alice) # Person(name='Alice', age=30, city='Unknown')

4. deque for efficient operations:
from collections import deque # Double-ended queue d = deque([1, 2, 3]) d.appendleft(0) # O(1) prepend d.append(4) # O(1) append print(d) # deque([0, 1, 2, 3, 4]) d.popleft() # Remove from left d.rotate(1) # Rotate right print(d) # deque([4, 1, 2, 3]) # Fixed-size deque (sliding window) recent = deque(maxlen=3) for i in range(5): recent.append(i) print(recent) # deque([2, 3, 4])

💡 Pro Tips:
• Counter is great for frequency analysis
• defaultdict eliminates key existence checks
• namedtuple is like a lightweight class
• deque is faster than list for left operations

Expected Output:
Counter: Counter({'apple': 3, 'banana': 2, 'cherry': 1}) Groups: {'a': [1, 3], 'b': [2]} Point: Point(x=3, y=4)

Requirements Checklist

Import from collections module
Use Counter to count elements
Use defaultdict with default factory
Create a namedtuple
Use deque for efficient operations
Print results to verify
Output
# Click "Run Code" to execute your Python code
Hints & Tips
• Import: from collections import Counter, defaultdict, namedtuple, deque
• Counter: Counter(['a', 'b', 'a']) → {'a': 2, 'b': 1}
• defaultdict: defaultdict(list) or defaultdict(int)
• namedtuple: Point = namedtuple('Point', ['x', 'y'])
• deque: deque([1,2,3], maxlen=5) for fixed size
Progress: 0/6
Score: 0/100
0%

Lab Results

Review feedback below