Utilities
Functools Module
Repeated expensive calculations slow applications, and repetitive function signatures clutter code. The functools module provides caching decorators for performance optimization, partial application for cleaner APIs, and reduction operations for aggregating sequences.
higher-order function
A function that takes other functions as arguments or returns functions - the foundation of functional programming patterns.
Reduce Operations
Aggregate a sequence to a single value:
reduce.py
Replay: real traced execution (multi-file project)
# functools.reduce examples
from functools import reduce
# Basic reduce
print("Basic reduce:")
# Sum with reduce
numbers = [1, 2, 3, 4, 5]
total = reduce(lambda x, y: x + y, numbers)
print(f"Sum of {numbers}: {total}")
# Product with reduce
product = reduce(lambda x, y: x * y, numbers)
print(f"Product of {numbers}: {product}")
# Max with reduce
values = [15, 42, 8, 93, 27]
maximum = reduce(lambda x, y: x if x > y else y, values)
print(f"Max of {values}: {maximum}")
# Reduce with initial value
print("\nReduce with initial value:")
# Sum with initial value
nums = [1, 2, 3, 4]
result = reduce(lambda x, y: x + y, nums, 10)
print(f"Sum of {nums} + 10: {result}")
# Count occurrences
words = ['apple', 'banana', 'apple', 'cherry', 'banana', 'apple']
count = reduce(lambda acc, word: acc + 1 if word == 'apple' else acc, words, 0)
print(f"Count 'apple' in {words}: {count}")
# String operations
print("\nString operations:")
# Concatenate strings
strings = ['Hello', ' ', 'World', '!']
message = reduce(lambda x, y: x + y, strings)
print(f"Concatenated: {message}")
# Build sentence
words_list = ['Python', 'is', 'awesome']
sentence = reduce(lambda x, y: f"{x} {y}", words_list)
print(f"Sentence: {sentence}")
# List operations
print("\nList operations:")
# Flatten nested lists
nested = [[1, 2], [3, 4], [5, 6]]
flattened = reduce(lambda x, y: x + y, nested)
print(f"Nested: {nested}")
print(f"Flattened: {flattened}")
# Merge dictionaries
dicts = [{'a': 1}, {'b': 2}, {'c': 3}]
merged = reduce(lambda x, y: {**x, **y}, dicts)
print(f"Merged dicts: {merged}")
# Mathematical operations
print("\nMathematical operations:")
# Factorial
n = 5
factorial = reduce(lambda x, y: x * y, range(1, n + 1))
print(f"{n}! = {factorial}")
# Power
base = 2
exponent = 10
power = reduce(lambda x, y: x * y, [base] * exponent)
print(f"{base}^{exponent} = {power}")
# GCD of list
import math
numbers_gcd = [48, 64, 80]
gcd = reduce(math.gcd, numbers_gcd)
print(f"GCD of {numbers_gcd}: {gcd}")
# Custom accumulator
print("\nCustom accumulator:")
# Build histogram
data = [1, 2, 2, 3, 3, 3, 4, 4, 4, 4]
histogram = reduce(
lambda acc, x: {**acc, x: acc.get(x, 0) + 1},
data,
{}
)
print(f"Data: {data}")
print(f"Histogram: {histogram}")
# Running totals
values_list = [10, 20, 30, 40]
def running_sum(acc, x):
return acc + [acc[-1] + x]
totals = reduce(running_sum, values_list, [0])
print(f"Values: {values_list}")
print(f"Running totals: {totals}")
# Comparison with alternatives
print("\nComparison with alternatives:")
nums_compare = [1, 2, 3, 4, 5]
# Using reduce
sum_reduce = reduce(lambda x, y: x + y, nums_compare)
print(f"reduce: {sum_reduce}")
# Using sum()
sum_builtin = sum(nums_compare)
print(f"sum(): {sum_builtin}")
# Using loop
sum_loop = 0
for n in nums_compare:
sum_loop += n
print(f"loop: {sum_loop}")
# Prefer built-ins when available
print(f"max() is clearer than reduce: {max(nums_compare)}")
# functools.reduce examples
from functools import reduce
# Basic reduce
print("Basic reduce:")
# Sum with reduce
numbers = [2, 4, 6]
total = reduce(lambda x, y: x + y, numbers)
print(f"Sum of {numbers}: {total}")
# Product with reduce
product = reduce(lambda x, y: x * y, numbers)
print(f"Product of {numbers}: {product}")
# Max with reduce
values = [15, 42, 8, 93, 27]
maximum = reduce(lambda x, y: x if x > y else y, values)
print(f"Max of {values}: {maximum}")
# Reduce with initial value
print("\nReduce with initial value:")
# Sum with initial value
nums = [1, 2, 3, 4]
result = reduce(lambda x, y: x + y, nums, 10)
print(f"Sum of {nums} + 10: {result}")
# Count occurrences
words = ['apple', 'banana', 'apple', 'cherry', 'banana', 'apple']
count = reduce(lambda acc, word: acc + 1 if word == 'apple' else acc, words, 0)
print(f"Count 'apple' in {words}: {count}")
# String operations
print("\nString operations:")
# Concatenate strings
strings = ['Hello', ' ', 'World', '!']
message = reduce(lambda x, y: x + y, strings)
print(f"Concatenated: {message}")
# Build sentence
words_list = ['Python', 'is', 'awesome']
sentence = reduce(lambda x, y: f"{x} {y}", words_list)
print(f"Sentence: {sentence}")
# List operations
print("\nList operations:")
# Flatten nested lists
nested = [[1, 2], [3, 4], [5, 6]]
flattened = reduce(lambda x, y: x + y, nested)
print(f"Nested: {nested}")
print(f"Flattened: {flattened}")
# Merge dictionaries
dicts = [{'a': 1}, {'b': 2}, {'c': 3}]
merged = reduce(lambda x, y: {**x, **y}, dicts)
print(f"Merged dicts: {merged}")
# Mathematical operations
print("\nMathematical operations:")
# Factorial
n = 5
factorial = reduce(lambda x, y: x * y, range(1, n + 1))
print(f"{n}! = {factorial}")
# Power
base = 2
exponent = 10
power = reduce(lambda x, y: x * y, [base] * exponent)
print(f"{base}^{exponent} = {power}")
# GCD of list
import math
numbers_gcd = [48, 64, 80]
gcd = reduce(math.gcd, numbers_gcd)
print(f"GCD of {numbers_gcd}: {gcd}")
# Custom accumulator
print("\nCustom accumulator:")
# Build histogram
data = [1, 2, 2, 3, 3, 3, 4, 4, 4, 4]
histogram = reduce(
lambda acc, x: {**acc, x: acc.get(x, 0) + 1},
data,
{}
)
print(f"Data: {data}")
print(f"Histogram: {histogram}")
# Running totals
values_list = [10, 20, 30, 40]
def running_sum(acc, x):
return acc + [acc[-1] + x]
totals = reduce(running_sum, values_list, [0])
print(f"Values: {values_list}")
print(f"Running totals: {totals}")
# Comparison with alternatives
print("\nComparison with alternatives:")
nums_compare = [1, 2, 3, 4, 5]
# Using reduce
sum_reduce = reduce(lambda x, y: x + y, nums_compare)
print(f"reduce: {sum_reduce}")
# Using sum()
sum_builtin = sum(nums_compare)
print(f"sum(): {sum_builtin}")
# Using loop
sum_loop = 0
for n in nums_compare:
sum_loop += n
print(f"loop: {sum_loop}")
# Prefer built-ins when available
print(f"max() is clearer than reduce: {max(nums_compare)}")
# functools.reduce examples
from functools import reduce
# Basic reduce
print("Basic reduce:")
# Sum with reduce
numbers = [10, 20, 30]
total = reduce(lambda x, y: x + y, numbers)
print(f"Sum of {numbers}: {total}")
# Product with reduce
product = reduce(lambda x, y: x * y, numbers)
print(f"Product of {numbers}: {product}")
# Max with reduce
values = [15, 42, 8, 93, 27]
maximum = reduce(lambda x, y: x if x > y else y, values)
print(f"Max of {values}: {maximum}")
# Reduce with initial value
print("\nReduce with initial value:")
# Sum with initial value
nums = [1, 2, 3, 4]
result = reduce(lambda x, y: x + y, nums, 10)
print(f"Sum of {nums} + 10: {result}")
# Count occurrences
words = ['apple', 'banana', 'apple', 'cherry', 'banana', 'apple']
count = reduce(lambda acc, word: acc + 1 if word == 'apple' else acc, words, 0)
print(f"Count 'apple' in {words}: {count}")
# String operations
print("\nString operations:")
# Concatenate strings
strings = ['Hello', ' ', 'World', '!']
message = reduce(lambda x, y: x + y, strings)
print(f"Concatenated: {message}")
# Build sentence
words_list = ['Python', 'is', 'awesome']
sentence = reduce(lambda x, y: f"{x} {y}", words_list)
print(f"Sentence: {sentence}")
# List operations
print("\nList operations:")
# Flatten nested lists
nested = [[1, 2], [3, 4], [5, 6]]
flattened = reduce(lambda x, y: x + y, nested)
print(f"Nested: {nested}")
print(f"Flattened: {flattened}")
# Merge dictionaries
dicts = [{'a': 1}, {'b': 2}, {'c': 3}]
merged = reduce(lambda x, y: {**x, **y}, dicts)
print(f"Merged dicts: {merged}")
# Mathematical operations
print("\nMathematical operations:")
# Factorial
n = 5
factorial = reduce(lambda x, y: x * y, range(1, n + 1))
print(f"{n}! = {factorial}")
# Power
base = 2
exponent = 10
power = reduce(lambda x, y: x * y, [base] * exponent)
print(f"{base}^{exponent} = {power}")
# GCD of list
import math
numbers_gcd = [48, 64, 80]
gcd = reduce(math.gcd, numbers_gcd)
print(f"GCD of {numbers_gcd}: {gcd}")
# Custom accumulator
print("\nCustom accumulator:")
# Build histogram
data = [1, 2, 2, 3, 3, 3, 4, 4, 4, 4]
histogram = reduce(
lambda acc, x: {**acc, x: acc.get(x, 0) + 1},
data,
{}
)
print(f"Data: {data}")
print(f"Histogram: {histogram}")
# Running totals
values_list = [10, 20, 30, 40]
def running_sum(acc, x):
return acc + [acc[-1] + x]
totals = reduce(running_sum, values_list, [0])
print(f"Values: {values_list}")
print(f"Running totals: {totals}")
# Comparison with alternatives
print("\nComparison with alternatives:")
nums_compare = [1, 2, 3, 4, 5]
# Using reduce
sum_reduce = reduce(lambda x, y: x + y, nums_compare)
print(f"reduce: {sum_reduce}")
# Using sum()
sum_builtin = sum(nums_compare)
print(f"sum(): {sum_builtin}")
# Using loop
sum_loop = 0
for n in nums_compare:
sum_loop += n
print(f"loop: {sum_loop}")
# Prefer built-ins when available
print(f"max() is clearer than reduce: {max(nums_compare)}")
numbers ← [1, 2, 3, 4, 5], total ← 15, product ← 120, values ← [15, 42, 8, 93, 27]
5# Basic reduce6print("Basic reduce:")78# Sum with reduce9numbers→ [1, 2, 3, 4, 5] = [1, 2, 3, 4, 5] #@numbers=[2, 4, 6], [10, 20, 30]10total→ 15 = reduce(lambda x, y: x + y, numbers[1, 2, 3, 4, 5])11print(f"Sum of {numbers[1, 2, 3, 4, 5]}: {total15}")1213# Product with reduce14product→ 120 = reduce(lambda x, y: x * y, numbers[1, 2, 3, 4, 5])15print(f"Product of {numbers[1, 2, 3, 4, 5]}: {product120}")1617# Max with reduce18values→ [15, 42, 8, 93, 27] = [15, 42, 8, 93, 27]19maximum→ 93 = reduce(lambda x, y: x if x > y else y, values[15, 42, 8, 93, 27])20print(f"Max of {values[15, 42, 8, 93, 27]}: {maximum93}")2122# Reduce with initial value23print("\nReduce with initial value:")2425# Sum with initial value26nums→ [1, 2, 3, 4] = [1, 2, 3, 4]27result→ 20 = reduce(lambda x, y: x + y, nums[1, 2, 3, 4], 10)28print(f"Sum of {nums[1, 2, 3, 4]} + 10: {result20}")2930# Count occurrences31words→ ['apple', 'banana', 'apple', 'cherry', 'banana', 'apple'] = ['apple', 'banana', 'apple', 'cherry', 'banana', 'apple']32count→ 3 = reduce(lambda acc, word: acc + 1 if word == 'apple' else acc, words['apple', 'banana', 'apple', 'cherry', 'banana', 'apple'], 0)33print(f"Count 'apple' in {words['apple', 'banana', 'apple', 'cherry', 'banana', 'apple']}: {count3}")3435# String operations36print("\nString operations:")3738# Concatenate strings39strings→ ['Hello', ' ', 'World', '!'] = ['Hello', ' ', 'World', '!']40message→ Hello World! = reduce(lambda x, y: x + y, strings['Hello', ' ', 'World', '!'])41print(f"Concatenated: {messageHello World!}")4243# Build sentence44words_list→ ['Python', 'is', 'awesome'] = ['Python', 'is', 'awesome']45sentence→ Python is awesome = reduce(lambda x, y: f"{x} {y}", words_list['Python', 'is', 'awesome'])46print(f"Sentence: {sentencePython is awesome}")4748# List operations49print("\nList operations:")5051# Flatten nested lists52nested→ [[1, 2], [3, 4], [5, 6]] = [[1, 2], [3, 4], [5, 6]]53flattened→ [1, 2, 3, 4, 5, 6] = reduce(lambda x, y: x + y, nested[[1, 2], [3, 4], [5, 6]])54print(f"Nested: {nested[[1, 2], [3, 4], [5, 6]]}")55print(f"Flattened: {flattened[1, 2, 3, 4, 5, 6]}")5657# Merge dictionaries58dicts→ [{'a': 1}, {'b': 2}, {'c': 3}] = [{'a': 1}, {'b': 2}, {'c': 3}]59merged→ {'a': 1, 'b': 2, 'c': 3} = reduce(lambda x, y: {**x, **y}, dicts[{'a': 1}, {'b': 2}, {'c': 3}])60print(f"Merged dicts: {merged{'a': 1, 'b': 2, 'c': 3}}")6162# Mathematical operations63print("\nMathematical operations:")6465# Factorial66n→ 5 = 567factorial→ 120 = reduce(lambda x, y: x * y, range(1, n5 + 1))68print(f"{n5}! = {factorial120}")6970# Power71base→ 2 = 272exponent→ 10 = 1073power→ 1024 = reduce(lambda x, y: x * y, [base2] * exponent10)74print(f"{base2}^{exponent10} = {power1024}")7576# GCD of list77import math78numbers_gcd→ [48, 64, 80] = [48, 64, 80]79gcd→ 16 = reduce(math.gcd<built-in function gcd>, numbers_gcd[48, 64, 80])80print(f"GCD of {numbers_gcd[48, 64, 80]}: {gcd16}")8182# Custom accumulator83print("\nCustom accumulator:")8485# Build histogram86data→ [1, 2, 2, 3, 3, 3, 4, 4, 4, 4] = [1, 2, 2, 3, 3, 3, 4, 4, 4, 4]87histogram→ {1: 1, 2: 2, 3: 3, 4: 4} = reduce(88 lambda acc, x: {**acc, x: acc.get(x, 0) + 1},89 data[1, 2, 2, 3, 3, 3, 4, 4, 4, 4],90 {}91)92print(f"Data: {data[1, 2, 2, 3, 3, 3, 4, 4, 4, 4]}")93print(f"Histogram: {histogram{1: 1, 2: 2, 3: 3, 4: 4}}")9495# Running totals96values_list→ [10, 20, 30, 40] = [10, 20, 30, 40]97def running_sum(acc, x):98 return acc + [acc[-1] + x]99100totals = reduce(running_sum⟨function running_sum A⟩, values_list[10, 20, 30, 40], [0])101print(f"Values: {values_list}")outputBasic reduce: Sum of [1, 2, 3, 4, 5]: 15 Product of [1, 2, 3, 4, 5]: 120 Max of [15, 42, 8, 93, 27]: 93 Reduce with initial value: Sum of [1, 2, 3, 4] + 10: 20 Count 'apple' in ['apple', 'banana', 'apple', 'cherry', 'banana', 'apple']: 3 String operations: Concatenated: Hello World! Sentence: Python is awesome List operations: Nested: [[1, 2], [3, 4], [5, 6]] Flattened: [1, 2, 3, 4, 5, 6] Merged dicts: {'a': 1, 'b': 2, 'c': 3} Mathematical operations: 5! = 120 2^10 = 1024 GCD of [48, 64, 80]: 16 Custom accumulator: Data: [1, 2, 2, 3, 3, 3, 4, 4, 4, 4] Histogram: {1: 1, 2: 2, 3: 3, 4: 4}def running_sum(acc, x):
pass 1 of 496values_list = [10, 20, 30, 40]97def running_sum(acc[0], x10):98 return acc[0] + [acc[-1]0 + x10]All 4 passes — pass 1 is the card above pass accxacc[-1]1 [0] 10 0 2 [0, 10] 20 10 3 [0, 10, 30] 30 30 4 [0, 10, 30, 60] 40 60 totals ← [0, 10, 30, 60, 100], nums_compare ← [1, 2, 3, 4, 5]
100totals→ [0, 10, 30, 60, 100] = reduce(running_sum⟨function running_sum A⟩, values_list[10, 20, 30, 40], [0])101print(f"Values: {values_list[10, 20, 30, 40]}")102print(f"Running totals: {totals[0, 10, 30, 60, 100]}")103104# Comparison with alternatives105print("\nComparison with alternatives:")106107nums_compare→ [1, 2, 3, 4, 5] = [1, 2, 3, 4, 5]108109# Using reduce110sum_reduce→ 15 = reduce(lambda x, y: x + y, nums_compare[1, 2, 3, 4, 5])111print(f"reduce: {sum_reduce15}")112113# Using sum()114sum_builtin→ 15 = sum(nums_compare[1, 2, 3, 4, 5])115print(f"sum(): {sum_builtin15}")116117# Using loop118sum_loop→ 0 = 0119for n in nums_compare:outputValues: [10, 20, 30, 40] Running totals: [0, 10, 30, 60, 100] Comparison with alternatives: reduce: 15 sum(): 15sum_loop ← 1
pass 1 of 5118sum_loop = 0119for n1 in nums_compare[1, 2, 3, 4, 5]:120 sum_loop→ 1 += n1121print(f"loop: {sum_loop}")All 5 passes — pass 1 is the card above pass nsum_loop1 1 0 → 1 2 2 1 → 3 3 3 3 → 6 4 4 6 → 10 5 5 10 → 15 print(f"loop: {sum_loop}")
120 sum_loop += n121print(f"loop: {sum_loop15}")122123# Prefer built-ins when available124print(f"max() is clearer than reduce: {max(nums_compare[1, 2, 3, 4, 5])}")outputloop: 15 max() is clearer than reduce: 5
numbers ← [2, 4, 6], total ← 12, product ← 48, values ← [15, 42, 8, 93, 27]
5# Basic reduce6print("Basic reduce:")78# Sum with reduce9numbers→ [2, 4, 6] = [2, 4, 6]10total→ 12 = reduce(lambda x, y: x + y, numbers[2, 4, 6])11print(f"Sum of {numbers[2, 4, 6]}: {total12}")1213# Product with reduce14product→ 48 = reduce(lambda x, y: x * y, numbers[2, 4, 6])15print(f"Product of {numbers[2, 4, 6]}: {product48}")1617# Max with reduce18values→ [15, 42, 8, 93, 27] = [15, 42, 8, 93, 27]19maximum→ 93 = reduce(lambda x, y: x if x > y else y, values[15, 42, 8, 93, 27])20print(f"Max of {values[15, 42, 8, 93, 27]}: {maximum93}")2122# Reduce with initial value23print("\nReduce with initial value:")2425# Sum with initial value26nums→ [1, 2, 3, 4] = [1, 2, 3, 4]27result→ 20 = reduce(lambda x, y: x + y, nums[1, 2, 3, 4], 10)28print(f"Sum of {nums[1, 2, 3, 4]} + 10: {result20}")2930# Count occurrences31words→ ['apple', 'banana', 'apple', 'cherry', 'banana', 'apple'] = ['apple', 'banana', 'apple', 'cherry', 'banana', 'apple']32count→ 3 = reduce(lambda acc, word: acc + 1 if word == 'apple' else acc, words['apple', 'banana', 'apple', 'cherry', 'banana', 'apple'], 0)33print(f"Count 'apple' in {words['apple', 'banana', 'apple', 'cherry', 'banana', 'apple']}: {count3}")3435# String operations36print("\nString operations:")3738# Concatenate strings39strings→ ['Hello', ' ', 'World', '!'] = ['Hello', ' ', 'World', '!']40message→ Hello World! = reduce(lambda x, y: x + y, strings['Hello', ' ', 'World', '!'])41print(f"Concatenated: {messageHello World!}")4243# Build sentence44words_list→ ['Python', 'is', 'awesome'] = ['Python', 'is', 'awesome']45sentence→ Python is awesome = reduce(lambda x, y: f"{x} {y}", words_list['Python', 'is', 'awesome'])46print(f"Sentence: {sentencePython is awesome}")4748# List operations49print("\nList operations:")5051# Flatten nested lists52nested→ [[1, 2], [3, 4], [5, 6]] = [[1, 2], [3, 4], [5, 6]]53flattened→ [1, 2, 3, 4, 5, 6] = reduce(lambda x, y: x + y, nested[[1, 2], [3, 4], [5, 6]])54print(f"Nested: {nested[[1, 2], [3, 4], [5, 6]]}")55print(f"Flattened: {flattened[1, 2, 3, 4, 5, 6]}")5657# Merge dictionaries58dicts→ [{'a': 1}, {'b': 2}, {'c': 3}] = [{'a': 1}, {'b': 2}, {'c': 3}]59merged→ {'a': 1, 'b': 2, 'c': 3} = reduce(lambda x, y: {**x, **y}, dicts[{'a': 1}, {'b': 2}, {'c': 3}])60print(f"Merged dicts: {merged{'a': 1, 'b': 2, 'c': 3}}")6162# Mathematical operations63print("\nMathematical operations:")6465# Factorial66n→ 5 = 567factorial→ 120 = reduce(lambda x, y: x * y, range(1, n5 + 1))68print(f"{n5}! = {factorial120}")6970# Power71base→ 2 = 272exponent→ 10 = 1073power→ 1024 = reduce(lambda x, y: x * y, [base2] * exponent10)74print(f"{base2}^{exponent10} = {power1024}")7576# GCD of list77import math78numbers_gcd→ [48, 64, 80] = [48, 64, 80]79gcd→ 16 = reduce(math.gcd<built-in function gcd>, numbers_gcd[48, 64, 80])80print(f"GCD of {numbers_gcd[48, 64, 80]}: {gcd16}")8182# Custom accumulator83print("\nCustom accumulator:")8485# Build histogram86data→ [1, 2, 2, 3, 3, 3, 4, 4, 4, 4] = [1, 2, 2, 3, 3, 3, 4, 4, 4, 4]87histogram→ {1: 1, 2: 2, 3: 3, 4: 4} = reduce(88 lambda acc, x: {**acc, x: acc.get(x, 0) + 1},89 data[1, 2, 2, 3, 3, 3, 4, 4, 4, 4],90 {}91)92print(f"Data: {data[1, 2, 2, 3, 3, 3, 4, 4, 4, 4]}")93print(f"Histogram: {histogram{1: 1, 2: 2, 3: 3, 4: 4}}")9495# Running totals96values_list→ [10, 20, 30, 40] = [10, 20, 30, 40]97def running_sum(acc, x):98 return acc + [acc[-1] + x]99100totals = reduce(running_sum⟨function running_sum A⟩, values_list[10, 20, 30, 40], [0])101print(f"Values: {values_list}")outputBasic reduce: Sum of [2, 4, 6]: 12 Product of [2, 4, 6]: 48 Max of [15, 42, 8, 93, 27]: 93 Reduce with initial value: Sum of [1, 2, 3, 4] + 10: 20 Count 'apple' in ['apple', 'banana', 'apple', 'cherry', 'banana', 'apple']: 3 String operations: Concatenated: Hello World! Sentence: Python is awesome List operations: Nested: [[1, 2], [3, 4], [5, 6]] Flattened: [1, 2, 3, 4, 5, 6] Merged dicts: {'a': 1, 'b': 2, 'c': 3} Mathematical operations: 5! = 120 2^10 = 1024 GCD of [48, 64, 80]: 16 Custom accumulator: Data: [1, 2, 2, 3, 3, 3, 4, 4, 4, 4] Histogram: {1: 1, 2: 2, 3: 3, 4: 4}def running_sum(acc, x):
pass 1 of 496values_list = [10, 20, 30, 40]97def running_sum(acc[0], x10):98 return acc[0] + [acc[-1]0 + x10]All 4 passes — pass 1 is the card above pass accxacc[-1]1 [0] 10 0 2 [0, 10] 20 10 3 [0, 10, 30] 30 30 4 [0, 10, 30, 60] 40 60 totals ← [0, 10, 30, 60, 100], nums_compare ← [1, 2, 3, 4, 5]
100totals→ [0, 10, 30, 60, 100] = reduce(running_sum⟨function running_sum A⟩, values_list[10, 20, 30, 40], [0])101print(f"Values: {values_list[10, 20, 30, 40]}")102print(f"Running totals: {totals[0, 10, 30, 60, 100]}")103104# Comparison with alternatives105print("\nComparison with alternatives:")106107nums_compare→ [1, 2, 3, 4, 5] = [1, 2, 3, 4, 5]108109# Using reduce110sum_reduce→ 15 = reduce(lambda x, y: x + y, nums_compare[1, 2, 3, 4, 5])111print(f"reduce: {sum_reduce15}")112113# Using sum()114sum_builtin→ 15 = sum(nums_compare[1, 2, 3, 4, 5])115print(f"sum(): {sum_builtin15}")116117# Using loop118sum_loop→ 0 = 0119for n in nums_compare:outputValues: [10, 20, 30, 40] Running totals: [0, 10, 30, 60, 100] Comparison with alternatives: reduce: 15 sum(): 15sum_loop ← 1
pass 1 of 5118sum_loop = 0119for n1 in nums_compare[1, 2, 3, 4, 5]:120 sum_loop→ 1 += n1121print(f"loop: {sum_loop}")All 5 passes — pass 1 is the card above pass nsum_loop1 1 0 → 1 2 2 1 → 3 3 3 3 → 6 4 4 6 → 10 5 5 10 → 15 print(f"loop: {sum_loop}")
120 sum_loop += n121print(f"loop: {sum_loop15}")122123# Prefer built-ins when available124print(f"max() is clearer than reduce: {max(nums_compare[1, 2, 3, 4, 5])}")outputloop: 15 max() is clearer than reduce: 5
numbers ← [10, 20, 30], total ← 60, product ← 6000, values ← [15, 42, 8, 93, 27]
5# Basic reduce6print("Basic reduce:")78# Sum with reduce9numbers→ [10, 20, 30] = [10, 20, 30]10total→ 60 = reduce(lambda x, y: x + y, numbers[10, 20, 30])11print(f"Sum of {numbers[10, 20, 30]}: {total60}")1213# Product with reduce14product→ 6000 = reduce(lambda x, y: x * y, numbers[10, 20, 30])15print(f"Product of {numbers[10, 20, 30]}: {product6000}")1617# Max with reduce18values→ [15, 42, 8, 93, 27] = [15, 42, 8, 93, 27]19maximum→ 93 = reduce(lambda x, y: x if x > y else y, values[15, 42, 8, 93, 27])20print(f"Max of {values[15, 42, 8, 93, 27]}: {maximum93}")2122# Reduce with initial value23print("\nReduce with initial value:")2425# Sum with initial value26nums→ [1, 2, 3, 4] = [1, 2, 3, 4]27result→ 20 = reduce(lambda x, y: x + y, nums[1, 2, 3, 4], 10)28print(f"Sum of {nums[1, 2, 3, 4]} + 10: {result20}")2930# Count occurrences31words→ ['apple', 'banana', 'apple', 'cherry', 'banana', 'apple'] = ['apple', 'banana', 'apple', 'cherry', 'banana', 'apple']32count→ 3 = reduce(lambda acc, word: acc + 1 if word == 'apple' else acc, words['apple', 'banana', 'apple', 'cherry', 'banana', 'apple'], 0)33print(f"Count 'apple' in {words['apple', 'banana', 'apple', 'cherry', 'banana', 'apple']}: {count3}")3435# String operations36print("\nString operations:")3738# Concatenate strings39strings→ ['Hello', ' ', 'World', '!'] = ['Hello', ' ', 'World', '!']40message→ Hello World! = reduce(lambda x, y: x + y, strings['Hello', ' ', 'World', '!'])41print(f"Concatenated: {messageHello World!}")4243# Build sentence44words_list→ ['Python', 'is', 'awesome'] = ['Python', 'is', 'awesome']45sentence→ Python is awesome = reduce(lambda x, y: f"{x} {y}", words_list['Python', 'is', 'awesome'])46print(f"Sentence: {sentencePython is awesome}")4748# List operations49print("\nList operations:")5051# Flatten nested lists52nested→ [[1, 2], [3, 4], [5, 6]] = [[1, 2], [3, 4], [5, 6]]53flattened→ [1, 2, 3, 4, 5, 6] = reduce(lambda x, y: x + y, nested[[1, 2], [3, 4], [5, 6]])54print(f"Nested: {nested[[1, 2], [3, 4], [5, 6]]}")55print(f"Flattened: {flattened[1, 2, 3, 4, 5, 6]}")5657# Merge dictionaries58dicts→ [{'a': 1}, {'b': 2}, {'c': 3}] = [{'a': 1}, {'b': 2}, {'c': 3}]59merged→ {'a': 1, 'b': 2, 'c': 3} = reduce(lambda x, y: {**x, **y}, dicts[{'a': 1}, {'b': 2}, {'c': 3}])60print(f"Merged dicts: {merged{'a': 1, 'b': 2, 'c': 3}}")6162# Mathematical operations63print("\nMathematical operations:")6465# Factorial66n→ 5 = 567factorial→ 120 = reduce(lambda x, y: x * y, range(1, n5 + 1))68print(f"{n5}! = {factorial120}")6970# Power71base→ 2 = 272exponent→ 10 = 1073power→ 1024 = reduce(lambda x, y: x * y, [base2] * exponent10)74print(f"{base2}^{exponent10} = {power1024}")7576# GCD of list77import math78numbers_gcd→ [48, 64, 80] = [48, 64, 80]79gcd→ 16 = reduce(math.gcd<built-in function gcd>, numbers_gcd[48, 64, 80])80print(f"GCD of {numbers_gcd[48, 64, 80]}: {gcd16}")8182# Custom accumulator83print("\nCustom accumulator:")8485# Build histogram86data→ [1, 2, 2, 3, 3, 3, 4, 4, 4, 4] = [1, 2, 2, 3, 3, 3, 4, 4, 4, 4]87histogram→ {1: 1, 2: 2, 3: 3, 4: 4} = reduce(88 lambda acc, x: {**acc, x: acc.get(x, 0) + 1},89 data[1, 2, 2, 3, 3, 3, 4, 4, 4, 4],90 {}91)92print(f"Data: {data[1, 2, 2, 3, 3, 3, 4, 4, 4, 4]}")93print(f"Histogram: {histogram{1: 1, 2: 2, 3: 3, 4: 4}}")9495# Running totals96values_list→ [10, 20, 30, 40] = [10, 20, 30, 40]97def running_sum(acc, x):98 return acc + [acc[-1] + x]99100totals = reduce(running_sum⟨function running_sum A⟩, values_list[10, 20, 30, 40], [0])101print(f"Values: {values_list}")outputBasic reduce: Sum of [10, 20, 30]: 60 Product of [10, 20, 30]: 6000 Max of [15, 42, 8, 93, 27]: 93 Reduce with initial value: Sum of [1, 2, 3, 4] + 10: 20 Count 'apple' in ['apple', 'banana', 'apple', 'cherry', 'banana', 'apple']: 3 String operations: Concatenated: Hello World! Sentence: Python is awesome List operations: Nested: [[1, 2], [3, 4], [5, 6]] Flattened: [1, 2, 3, 4, 5, 6] Merged dicts: {'a': 1, 'b': 2, 'c': 3} Mathematical operations: 5! = 120 2^10 = 1024 GCD of [48, 64, 80]: 16 Custom accumulator: Data: [1, 2, 2, 3, 3, 3, 4, 4, 4, 4] Histogram: {1: 1, 2: 2, 3: 3, 4: 4}def running_sum(acc, x):
pass 1 of 496values_list = [10, 20, 30, 40]97def running_sum(acc[0], x10):98 return acc[0] + [acc[-1]0 + x10]All 4 passes — pass 1 is the card above pass accxacc[-1]1 [0] 10 0 2 [0, 10] 20 10 3 [0, 10, 30] 30 30 4 [0, 10, 30, 60] 40 60 totals ← [0, 10, 30, 60, 100], nums_compare ← [1, 2, 3, 4, 5]
100totals→ [0, 10, 30, 60, 100] = reduce(running_sum⟨function running_sum A⟩, values_list[10, 20, 30, 40], [0])101print(f"Values: {values_list[10, 20, 30, 40]}")102print(f"Running totals: {totals[0, 10, 30, 60, 100]}")103104# Comparison with alternatives105print("\nComparison with alternatives:")106107nums_compare→ [1, 2, 3, 4, 5] = [1, 2, 3, 4, 5]108109# Using reduce110sum_reduce→ 15 = reduce(lambda x, y: x + y, nums_compare[1, 2, 3, 4, 5])111print(f"reduce: {sum_reduce15}")112113# Using sum()114sum_builtin→ 15 = sum(nums_compare[1, 2, 3, 4, 5])115print(f"sum(): {sum_builtin15}")116117# Using loop118sum_loop→ 0 = 0119for n in nums_compare:outputValues: [10, 20, 30, 40] Running totals: [0, 10, 30, 60, 100] Comparison with alternatives: reduce: 15 sum(): 15sum_loop ← 1
pass 1 of 5118sum_loop = 0119for n1 in nums_compare[1, 2, 3, 4, 5]:120 sum_loop→ 1 += n1121print(f"loop: {sum_loop}")All 5 passes — pass 1 is the card above pass nsum_loop1 1 0 → 1 2 2 1 → 3 3 3 3 → 6 4 4 6 → 10 5 5 10 → 15 print(f"loop: {sum_loop}")
120 sum_loop += n121print(f"loop: {sum_loop15}")122123# Prefer built-ins when available124print(f"max() is clearer than reduce: {max(nums_compare[1, 2, 3, 4, 5])}")outputloop: 15 max() is clearer than reduce: 5
reduce()
Applies a function cumulatively to sequence items, reducing them to a single value - like folding a list into one result.
Caching with lru_cache
Automatically cache function results:
cache.py
Replay: real traced execution (multi-file project)
# functools.lru_cache examples
from functools import lru_cache
import time
# Basic caching
print("Basic caching:")
@lru_cache(maxsize=128)
def expensive_function(n):
"""Simulate expensive computation."""
time.sleep(0.001) # Simulate delay
return n * n
# First call computes; second call is served from the cache
result1 = expensive_function(10)
result2 = expensive_function(10)
initial_info = expensive_function.cache_info()
print(f"First call: {result1}")
print(f"Second call: {result2}")
print(f"Cache hits: {initial_info.hits}, misses: {initial_info.misses}")
# Fibonacci with cache
print("\nFibonacci with cache:")
@lru_cache(maxsize=None) # Unlimited cache
def fibonacci(n):
if n < 2:
return n
return fibonacci(n - 1) + fibonacci(n - 2)
result = fibonacci(12)
print(f"fibonacci(12) = {result}")
# Without cache would take much longer
def fib_no_cache(n):
if n < 2:
return n
return fib_no_cache(n - 1) + fib_no_cache(n - 2)
result_no_cache = fib_no_cache(8) # Much smaller n
print(f"\nWithout cache:")
print(f"fibonacci(8) = {result_no_cache}")
# Cache info
print("\nCache info:")
@lru_cache(maxsize=3)
def compute(x):
return x * 2
# Make some calls
for i in range(5):
compute(i)
# Check hits
for i in range(3):
compute(i)
info = compute.cache_info()
print(f"Hits: {info.hits}")
print(f"Misses: {info.misses}")
print(f"Size: {info.currsize}")
print(f"Max size: {info.maxsize}")
# Cache clear
print("\nCache clear:")
@lru_cache(maxsize=128)
def add(x, y):
print(f" Computing {x} + {y}")
return x + y
print("First calls:")
add(1, 2)
add(3, 4)
add(1, 2) # Cached
print("\nAfter clearing:")
add.cache_clear()
add(1, 2) # Not cached anymore
# Maxsize effects
print("\nMaxsize effects:")
@lru_cache(maxsize=2)
def limited(n):
return n * n
# Fill cache
limited(1) # Miss
limited(2) # Miss
limited(1) # Hit
# Evict oldest
limited(3) # Miss, evicts 2
limited(1) # Hit
limited(2) # Miss (was evicted)
info = limited.cache_info()
print(f"Hits: {info.hits}, Misses: {info.misses}")
# Prime checking with cache
print("\nPrime checking with cache:")
@lru_cache(maxsize=1000)
def is_prime(n):
if n < 2:
return False
if n == 2:
return True
if n % 2 == 0:
return False
for i in range(3, int(n**0.5) + 1, 2):
if n % i == 0:
return False
return True
# Check primes multiple times
primes = [p for p in range(30) if is_prime(p)]
print(f"Primes < 30: {len(primes)}")
# Recheck (cached)
primes_again = [p for p in range(30) if is_prime(p)]
print(f"Rechecking returns same values: {primes_again == primes}")
info = is_prime.cache_info()
print(f"Cache: {info.hits} hits, {info.misses} misses")
# Distance calculation
print("\nDistance calculation:")
@lru_cache(maxsize=256)
def distance(x1, y1, x2, y2):
"""Calculate Euclidean distance."""
return ((x2 - x1)**2 + (y2 - y1)**2)**0.5
# Calculate distances
points = [(0, 0), (3, 4), (1, 1), (0, 0), (3, 4)]
for i in range(len(points)):
for j in range(i + 1, len(points)):
d = distance(*points[i], *points[j])
print(f" {points[i]} to {points[j]}: {d:.2f}")
info = distance.cache_info()
print(f"Cache: {info.hits} hits, {info.misses} misses")
# Memoization pattern
print("\nMemoization pattern:")
@lru_cache(maxsize=None)
def count_paths(m, n):
"""Count paths in m x n grid."""
if m == 1 or n == 1:
return 1
return count_paths(m - 1, n) + count_paths(m, n - 1)
result = count_paths(5, 5)
print(f"Paths in 5x5 grid: {result}")
info = count_paths.cache_info()
print(f"Cache efficiency: {info.hits}/{info.hits + info.misses} hits")
print("Basic caching:")
6# Basic caching7print("Basic caching:")89@lru_cache(maxsize=128)10def expensive_function(n):11 """Simulate expensive computation."""12 time.sleep(0.001) # Simulate delay13 return n * n1415# First call computes; second call is served from the cache16result1 = expensive_function(10)17result2 = expensive_function(10)outputBasic caching:def expensive_function(n):
9@lru_cache(maxsize=128)10def expensive_function(n10):11 """Simulate expensive computation."""12 time<module 'time' (built-in)>.sleep(0.001) # Simulate delay13 return n10 * nresult1 ← 100, result2 ← 100, initial_info ← CacheInfo(hits=1, misses=1, maxsize=128, currsize=1)
15# First call computes; second call is served from the cache16result1→ 100 = expensive_function(10)17result2→ 100 = expensive_function(10)18initial_info→ CacheInfo(hits=1, misses=1, maxsize=128, currsize=1) = expensive_function⟨_lru_cache_wrapper A⟩.cache_info()1920print(f"First call: {result1100}")21print(f"Second call: {result2100}")22print(f"Cache hits: {initial_info.hits1}, misses: {initial_info.misses1}")2324# Fibonacci with cache25print("\nFibonacci with cache:")2627@lru_cache(maxsize=None) # Unlimited cache28def fibonacci(n):29 if n < 2:30 return n31 return fibonacci(n - 1) + fibonacci(n - 2)3233result = fibonacci(12)outputFirst call: 100 Second call: 100 Cache hits: 1, misses: 1 Fibonacci with cache:def fibonacci(n):
pass 1 of 1327@lru_cache(maxsize=None) # Unlimited cache28def fibonacci(n12):29 if n < 2:30 return n31 return fibonacci(n12 - 1) + fibonacci(n - 2)13 passes — pass 1 is the card above pass n1 12 2 11 3 10 4 9 5 8 6 7 7 6 8 5 9 4 ⋯ 2 more passes ⋯ 12 1 13 0 if n < 2:
pass 1 of 228def fibonacci(n):29 if n1 < 2:30 return n131 return fibonacci(n - 1) + fibonacci(n - 2)if n < 2:
pass 2 of 228def fibonacci(n):29 if n0 < 2:30 return n031 return fibonacci(n - 1) + fibonacci(n - 2)result ← 144
33result→ 144 = fibonacci(12)3435print(f"fibonacci(12) = {result144}")3637# Without cache would take much longer38def fib_no_cache(n):39 if n < 2:40 return n41 return fib_no_cache(n - 1) + fib_no_cache(n - 2)4243result_no_cache = fib_no_cache(8) # Much smaller noutputfibonacci(12) = 144def fib_no_cache(n):
pass 1 of 6737# Without cache would take much longer38def fib_no_cache(n8):39 if n < 2:40 return n41 return fib_no_cache(n8 - 1) + fib_no_cache(n - 2)67 passes — pass 1 is the card above pass n1 8 2 7 3 6 4 5 5 4 6 3 7 2 8 1 9 0 ⋯ 56 more passes ⋯ 66 1 67 0 if n < 2:
pass 1 of 3438def fib_no_cache(n):39 if n1 < 2:40 return n141 return fib_no_cache(n - 1) + fib_no_cache(n - 2)34 passes — pass 1 is the card above pass n1 1 2 0 3 1 4 1 5 0 6 1 7 0 8 1 9 1 ⋯ 23 more passes ⋯ 33 1 34 0 result_no_cache ← 21
43result_no_cache→ 21 = fib_no_cache(8) # Much smaller n4445print(f"\nWithout cache:")46print(f"fibonacci(8) = {result_no_cache21}")4748# Cache info49print("\nCache info:")output Without cache: fibonacci(8) = 21 Cache info:for i in range(5):
pass 1 of 555# Make some calls56for i0 in range(5):57 compute(i0)All 5 passes — pass 1 is the card above pass i1 0 2 1 3 2 4 3 5 4 def compute(x):
pass 1 of 851@lru_cache(maxsize=3)52def compute(x0):53 return x0 * 2All 8 passes — pass 1 is the card above pass x1 0 2 1 3 2 4 3 5 4 6 0 7 1 8 2 compute(i)
56for i in range(5):57 compute(i0)compute(i)
56for i in range(5):57 compute(i1)compute(i)
56for i in range(5):57 compute(i2)compute(i)
56for i in range(5):57 compute(i3)compute(i)
56for i in range(5):57 compute(i4)for i in range(3):
pass 1 of 359# Check hits60for i0 in range(3):61 compute(i0)All 3 passes — pass 1 is the card above pass i1 0 2 1 3 2 compute(i)
60for i in range(3):61 compute(i0)compute(i)
60for i in range(3):61 compute(i1)compute(i)
60for i in range(3):61 compute(i2)info ← CacheInfo(hits=0, misses=8, maxsize=3, currsize=3)
63info→ CacheInfo(hits=0, misses=8, maxsize=3, currsize=3) = compute⟨_lru_cache_wrapper B⟩.cache_info()64print(f"Hits: {info.hits0}")65print(f"Misses: {info.misses8}")66print(f"Size: {info.currsize3}")67print(f"Max size: {info.maxsize3}")6869# Cache clear70print("\nCache clear:")7172@lru_cache(maxsize=128)73def add(x, y):74 print(f" Computing {x} + {y}")75 return x + y7677print("First calls:")78add(1, 2)79add(3, 4)outputHits: 0 Misses: 8 Size: 3 Max size: 3 Cache clear: First calls:def add(x, y):
pass 1 of 372@lru_cache(maxsize=128)73def add(x1, y2):74 print(f" Computing {x1} + {y2}")75 return x1 + y2output Computing 1 + 2All 3 passes — pass 1 is the card above pass xy1 1 2 2 3 4 3 1 2 add(1, 2)
77print("First calls:")78add(1, 2)79add(3, 4)80add(1, 2) # Cachedadd.cache_clear()
78add(1, 2)79add(3, 4)80add(1, 2) # Cached8182print("\nAfter clearing:")83add⟨_lru_cache_wrapper C⟩.cache_clear()84add(1, 2) # Not cached anymoreoutput After clearing:add(1, 2) # Not cached anymore
83add.cache_clear()84add(1, 2) # Not cached anymore8586# Maxsize effects87print("\nMaxsize effects:")8889@lru_cache(maxsize=2)90def limited(n):91 return n * n9293# Fill cache94limited(1) # Miss95limited(2) # Missoutput Maxsize effects:def limited(n):
pass 1 of 489@lru_cache(maxsize=2)90def limited(n1):91 return n1 * nAll 4 passes — pass 1 is the card above pass n1 1 2 2 3 3 4 2 limited(1) # Miss
93# Fill cache94limited(1) # Miss95limited(2) # Miss96limited(1) # Hitlimited(2) # Miss
94limited(1) # Miss95limited(2) # Miss96limited(1) # Hit9798# Evict oldest99limited(3) # Miss, evicts 2100limited(1) # Hitlimited(3) # Miss, evicts 2
98# Evict oldest99limited(3) # Miss, evicts 2100limited(1) # Hit101limited(2) # Miss (was evicted)info ← CacheInfo(hits=2, misses=4, maxsize=2, currsize=2)
100limited(1) # Hit101limited(2) # Miss (was evicted)102103info→ CacheInfo(hits=2, misses=4, maxsize=2, currsize=2) = limited⟨_lru_cache_wrapper D⟩.cache_info()104print(f"Hits: {info.hits2}, Misses: {info.misses4}")105106# Prime checking with cache107print("\nPrime checking with cache:")108109@lru_cache(maxsize=1000)110def is_prime(n):111 if n < 2:112 return False113 if n == 2:114 return True115 if n % 2 == 0:116 return False117 for i in range(3, int(n**0.5) + 1, 2):118 if n % i == 0:119 return False120 return True121122# Check primes multiple times123primes = [p for p in range(30) if is_prime(p)]124print(f"Primes < 30: {len(primes)}")outputHits: 2, Misses: 4 Prime checking with cache:def is_prime(n):
pass 1 of 30109@lru_cache(maxsize=1000)110def is_prime(n0):111 if n < 2:112 return False30 passes — pass 1 is the card above pass n1 0 2 1 3 2 4 3 5 4 6 5 7 6 8 7 9 8 ⋯ 19 more passes ⋯ 29 28 30 29 if n < 2:
pass 1 of 2110def is_prime(n):111 if n0 < 2:112 return False113 if n == 2:if n < 2:
pass 2 of 2110def is_prime(n):111 if n1 < 2:112 return False113 if n == 2:if n == 2:
112 return False113if n2 == 2:114 return True115if n % 2 == 0:if n % 2 == 0:
pass 1 of 13114 return True115if n4 % 2 == 0:116 return False117for i in range(3, int(n**0.5) + 1, 2):13 passes — pass 1 is the card above pass n1 4 2 6 3 8 4 10 5 12 6 14 7 16 8 18 9 20 ⋯ 2 more passes ⋯ 12 26 13 28 for i in range(3, int(n**0.5) + 1, 2):
pass 1 of 13116 return False117for i3 in range(3, int(n9**0.5) + 1, 2):118 if n % i == 0:119 return False13 passes — pass 1 is the card above pass in1 3 9 2 3 11 3 3 13 4 3 15 5 3 17 6 3 19 7 3 21 8 3 23 9 3 25 ⋯ 2 more passes ⋯ 12 3 29 13 5 29 if n % i == 0:
pass 1 of 5117for i in range(3, int(n**0.5) + 1, 2):118 if n9 % i3 == 0:119 return False120return TrueAll 5 passes — pass 1 is the card above pass ni1 9 3 2 15 3 3 21 3 4 25 5 5 27 3 return True
119 return False120return Truereturn True
119 return False120return Truereturn True
119 return False120return Truereturn True
119 return False120return Truereturn True
119 return False120return Truereturn True
119 return False120return Trueprimes ← [2, 3, 5, 7, 11, 13, 17, 19, 23, 29], primes_again ← [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]
122# Check primes multiple times123primes→ [2, 3, 5, 7, 11, 13, 17, 19, 23, 29] = [p for p in range(30) if is_prime(p)]124print(f"Primes < 30: {len(primes[2, 3, 5, 7, 11, 13, 17, 19, 23, 29])}")125126# Recheck (cached)127primes_again→ [2, 3, 5, 7, 11, 13, 17, 19, 23, 29] = [p for p in range(30) if is_prime(p)]128print(f"Rechecking returns same values: {primes_again[2, 3, 5, 7, 11, 13, 17, 19, 23, 29] == primes[2, 3, 5, 7, 11, 13, 17, 19, 23, 29]}")129130info→ CacheInfo(hits=30, misses=30, maxsize=1000, currsize=30) = is_prime⟨_lru_cache_wrapper E⟩.cache_info()131print(f"Cache: {info.hits30} hits, {info.misses30} misses")132133# Distance calculation134print("\nDistance calculation:")135136@lru_cache(maxsize=256)137def distance(x1, y1, x2, y2):138 """Calculate Euclidean distance."""139 return ((x2 - x1)**2 + (y2 - y1)**2)**0.5140141# Calculate distances142points→ [(0, 0), (3, 4), (1, 1), (0, 0), (3, 4)] = [(0, 0), (3, 4), (1, 1), (0, 0), (3, 4)]outputPrimes < 30: 10 Rechecking returns same values: True Cache: 30 hits, 30 misses Distance calculation:for i in range(len(points)):
pass 1 of 5144for i0 in range(len(points[(0, 0), (3, 4), (1, 1), (0, 0), (3, 4)])):145 for j in range(i + 1, len(points)):146 d = distance(*points[i], *points[j])All 5 passes — pass 1 is the card above pass i1 0 2 1 3 2 4 3 5 4 for j in range(i + 1, len(points)):
pass 1 of 10144for i in range(len(points)):145 for j1 in range(i0 + 1, len(points[(0, 0), (3, 4), (1, 1), (0, 0), (3, 4)])):146 d = distance(*points[i](0, 0), *points[j](3, 4))147 print(f" {points[i]} to {points[j]}: {d:.2f}")All 10 passes — pass 1 is the card above pass jipoints[i]points[j]d1 1 0 (0, 0) (3, 4) — 2 2 0 (0, 0) (1, 1) — 3 3 0 (0, 0) (0, 0) — 4 4 0 (0, 0) (3, 4) 5.0 5 2 1 (3, 4) (1, 1) — 6 3 1 (3, 4) (0, 0) — 7 4 1 (3, 4) (3, 4) — 8 3 2 (1, 1) (0, 0) — 9 4 2 (1, 1) (3, 4) — 10 4 3 (0, 0) (3, 4) 5.0 def distance(x1, y1, x2, y2):
pass 1 of 8136@lru_cache(maxsize=256)137def distance(x10, y10, x23, y24):138 """Calculate Euclidean distance."""139 return ((x23 - x10)**2 + (y24 - y10)**2)**0.5All 8 passes — pass 1 is the card above pass x1y1x2y21 0 0 3 4 2 0 0 1 1 3 0 0 0 0 4 3 4 1 1 5 3 4 0 0 6 3 4 3 4 7 1 1 0 0 8 1 1 3 4 d ← 5.0
145for j in range(i + 1, len(points)):146 d→ 5.0 = distance(*points[i](0, 0), *points[j](3, 4))147 print(f" {points[i](0, 0)} to {points[j](3, 4)}: {d5.0:.2f}")output (0, 0) to (3, 4): 5.00d ← 1.4142135623730951
145for j in range(i + 1, len(points)):146 d→ 1.4142135623730951 = distance(*points[i](0, 0), *points[j](1, 1))147 print(f" {points[i](0, 0)} to {points[j](1, 1)}: {d1.4142135623730951:.2f}")output (0, 0) to (1, 1): 1.41d ← 0.0
145for j in range(i + 1, len(points)):146 d→ 0.0 = distance(*points[i](0, 0), *points[j](0, 0))147 print(f" {points[i](0, 0)} to {points[j](0, 0)}: {d0.0:.2f}")output (0, 0) to (0, 0): 0.00d ← 3.605551275463989
145for j in range(i + 1, len(points)):146 d→ 3.605551275463989 = distance(*points[i](3, 4), *points[j](1, 1))147 print(f" {points[i](3, 4)} to {points[j](1, 1)}: {d3.605551275463989:.2f}")output (3, 4) to (1, 1): 3.61d ← 5.0
145for j in range(i + 1, len(points)):146 d→ 5.0 = distance(*points[i](3, 4), *points[j](0, 0))147 print(f" {points[i](3, 4)} to {points[j](0, 0)}: {d5.0:.2f}")output (3, 4) to (0, 0): 5.00d ← 0.0
145for j in range(i + 1, len(points)):146 d→ 0.0 = distance(*points[i](3, 4), *points[j](3, 4))147 print(f" {points[i](3, 4)} to {points[j](3, 4)}: {d0.0:.2f}")output (3, 4) to (3, 4): 0.00d ← 1.4142135623730951
145for j in range(i + 1, len(points)):146 d→ 1.4142135623730951 = distance(*points[i](1, 1), *points[j](0, 0))147 print(f" {points[i](1, 1)} to {points[j](0, 0)}: {d1.4142135623730951:.2f}")output (1, 1) to (0, 0): 1.41d ← 3.605551275463989
145for j in range(i + 1, len(points)):146 d→ 3.605551275463989 = distance(*points[i](1, 1), *points[j](3, 4))147 print(f" {points[i](1, 1)} to {points[j](3, 4)}: {d3.605551275463989:.2f}")output (1, 1) to (3, 4): 3.61info ← CacheInfo(hits=2, misses=8, maxsize=256, currsize=8)
149info→ CacheInfo(hits=2, misses=8, maxsize=256, currsize=8) = distance⟨_lru_cache_wrapper F⟩.cache_info()150print(f"Cache: {info.hits2} hits, {info.misses8} misses")151152# Memoization pattern153print("\nMemoization pattern:")154155@lru_cache(maxsize=None)156def count_paths(m, n):157 """Count paths in m x n grid."""158 if m == 1 or n == 1:159 return 1160 return count_paths(m - 1, n) + count_paths(m, n - 1)161162result = count_paths(5, 5)163print(f"Paths in 5x5 grid: {result}")outputCache: 2 hits, 8 misses Memoization pattern:def count_paths(m, n):
pass 1 of 24155@lru_cache(maxsize=None)156def count_paths(m5, n5):157 """Count paths in m x n grid."""158 if m == 1 or n == 1:159 return 1160 return count_paths(m5 - 1, n5) + count_paths(m, n - 1)24 passes — pass 1 is the card above pass mn1 5 5 2 4 5 3 3 5 4 2 5 5 1 5 6 2 4 7 1 4 8 2 3 9 1 3 ⋯ 13 more passes ⋯ 23 5 2 24 5 1 if m == 1 or n == 1:
pass 1 of 8157"""Count paths in m x n grid."""158if m1 == 1 or n5 == 1:159 return 1160return count_paths(m - 1, n) + count_paths(m, n - 1)All 8 passes — pass 1 is the card above pass mn1 1 5 2 1 4 3 1 3 4 1 2 5 2 1 6 3 1 7 4 1 8 5 1 result ← 70, info ← CacheInfo(hits=9, misses=24, maxsize=None, currsize=24)
162result→ 70 = count_paths(5, 5)163print(f"Paths in 5x5 grid: {result70}")164165info→ CacheInfo(hits=9, misses=24, maxsize=None, currsize=24) = count_paths⟨_lru_cache_wrapper G⟩.cache_info()166print(f"Cache efficiency: {info.hits9}/{info.hits + info.misses24} hits")outputPaths in 5x5 grid: 70 Cache efficiency: 9/33 hits
lru_cache
Least Recently Used cache decorator that stores recent function results, dramatically speeding up recursive algorithms and repeated calculations.
Partial Function Application
Create specialized versions of functions:
partial.py
Replay: real traced execution (multi-file project)
# functools.partial examples
from functools import partial
# Basic partial
print("Basic partial:")
def multiply(x, y):
return x * y
# Create specialized functions
double = partial(multiply, 2)
triple = partial(multiply, 3)
print(f"double(5) = {double(5)}")
print(f"triple(5) = {triple(5)}")
# Partial with multiple args
print("\nPartial with multiple args:")
def power(base, exponent):
return base ** exponent
# Fix base
square = partial(power, exponent=2)
cube = partial(power, exponent=3)
print(f"square(5) = {square(5)}")
print(f"cube(5) = {cube(5)}")
# Fix exponent
power_of_2 = partial(power, 2)
power_of_10 = partial(power, 10)
print(f"2^8 = {power_of_2(8)}")
print(f"10^3 = {power_of_10(3)}")
# String formatting
print("\nString formatting:")
def format_message(prefix, message, suffix):
return f"{prefix}{message}{suffix}"
# Create specialized formatters
error = partial(format_message, "[ERROR] ", suffix="")
warning = partial(format_message, "[WARN] ", suffix="")
info = partial(format_message, "[INFO] ", suffix="")
print(error("File not found"))
print(warning("Deprecated function"))
print(info("Process started"))
# Sorting with partial
print("\nSorting with partial:")
# Sort by custom key
students = [
{'name': 'Alice', 'age': 20, 'grade': 85},
{'name': 'Bob', 'age': 22, 'grade': 92},
{'name': 'Charlie', 'age': 21, 'grade': 78}
]
from operator import itemgetter
# Create reusable key functions
by_name = partial(sorted, key=itemgetter('name'))
by_age = partial(sorted, key=itemgetter('age'))
by_grade = partial(sorted, key=itemgetter('grade'))
print("By name:")
for s in by_name(students):
print(f" {s['name']}: {s['grade']}")
print("By grade:")
for s in by_grade(students):
print(f" {s['name']}: {s['grade']}")
# File operations
print("\nFile operations:")
def read_file(filename, mode='r', encoding='utf-8'):
"""Simulate file reading."""
return f"Reading {filename} (mode={mode}, encoding={encoding})"
# Create specialized readers
read_text = partial(read_file, mode='r', encoding='utf-8')
read_binary = partial(read_file, mode='rb', encoding=None)
read_json = partial(read_file, mode='r', encoding='utf-8')
print(read_text('data.txt'))
print(read_binary('image.png'))
# Logging
print("\nLogging:")
def log(level, component, message):
print(f"[{level}] {component}: {message}")
# Create component-specific loggers
db_log = partial(log, component='Database')
api_log = partial(log, component='API')
cache_log = partial(log, component='Cache')
db_log(level='INFO', message='Connected to PostgreSQL')
api_log(level='WARN', message='Rate limit approaching')
cache_log(level='ERROR', message='Redis connection failed')
# Map with partial
print("\nMap with partial:")
def add(x, y):
return x + y
# Add 10 to each number
numbers = [1, 2, 3, 4, 5]
add_10 = partial(add, 10)
result = list(map(add_10, numbers))
print(f"Original: {numbers}")
print(f"Add 10: {result}")
# Filter with partial
print("\nFilter with partial:")
def greater_than(threshold, value):
return value > threshold
# Filter values > 50
values = [25, 60, 45, 80, 30, 95]
above_50 = partial(greater_than, 50)
filtered = list(filter(above_50, values))
print(f"Values: {values}")
print(f"Above 50: {filtered}")
# Callback functions
print("\nCallback functions:")
def process_data(data, validator, transformer):
if validator(data):
return transformer(data)
return None
def is_positive(x):
return x > 0
def is_even(x):
return x % 2 == 0
def square(x):
return x * x
# Create specialized processors
process_positive = partial(process_data, validator=is_positive, transformer=square)
process_even = partial(process_data, validator=is_even, transformer=square)
print(f"Process positive 5: {process_positive(5)}")
print(f"Process positive -3: {process_positive(-3)}")
print(f"Process even 4: {process_even(4)}")
print(f"Process even 3: {process_even(3)}")
# Partial attributes
print("\nPartial attributes:")
greet = partial(format_message, "Hello, ")
print(f"Function: {greet.func}")
print(f"Args: {greet.args}")
print(f"Keywords: {greet.keywords}")
double ← functools.partial(⟨function multiply A⟩, 2), triple ← functools.partial(⟨function multiply A⟩, 3)
5# Basic partial6print("Basic partial:")78def multiply(x, y):9 return x * y1011# Create specialized functions12double→ functools.partial(⟨function multiply A⟩, 2) = partial(multiply⟨function multiply A⟩, 2)13triple→ functools.partial(⟨function multiply A⟩, 3) = partial(multiply⟨function multiply A⟩, 3)1415print(f"double(5) = {double(5)}")16print(f"triple(5) = {triple(5)}")outputBasic partial:def multiply(x, y):
pass 1 of 28def multiply(x2, y5):9 return x2 * y5print(f"double(5) = {double(5)}")
15print(f"double(5) = {double(5)}")16print(f"triple(5) = {triple(5)}")outputdouble(5) = 10def multiply(x, y):
pass 2 of 28def multiply(x3, y5):9 return x3 * y5square ← functools.partial(⟨function power B⟩, exponent=2), cube ← functools.partial(⟨function power B⟩, exponent=3)
15print(f"double(5) = {double(5)}")16print(f"triple(5) = {triple(5)}")1718# Partial with multiple args19print("\nPartial with multiple args:")2021def power(base, exponent):22 return base ** exponent2324# Fix base25square→ functools.partial(⟨function power B⟩, exponent=2) = partial(power⟨function power B⟩, exponent=2)26cube→ functools.partial(⟨function power B⟩, exponent=3) = partial(power⟨function power B⟩, exponent=3)2728print(f"square(5) = {square(5)}")29print(f"cube(5) = {cube(5)}")outputtriple(5) = 15 Partial with multiple args:def power(base, exponent):
pass 1 of 421def power(base5, exponent2):22 return base5 ** exponent2All 4 passes — pass 1 is the card above pass baseexponent1 5 2 2 5 3 3 2 8 4 10 3 print(f"square(5) = {square(5)}")
28print(f"square(5) = {square(5)}")29print(f"cube(5) = {cube(5)}")outputsquare(5) = 25power_of_2 ← functools.partial(⟨function power B⟩, 2), power_of_10 ← functools.partial(⟨function power B⟩, 10)
28print(f"square(5) = {square(5)}")29print(f"cube(5) = {cube(5)}")3031# Fix exponent32power_of_2→ functools.partial(⟨function power B⟩, 2) = partial(power⟨function power B⟩, 2)33power_of_10→ functools.partial(⟨function power B⟩, 10) = partial(power⟨function power B⟩, 10)3435print(f"2^8 = {power_of_2(8)}")36print(f"10^3 = {power_of_10(3)}")outputcube(5) = 125print(f"2^8 = {power_of_2(8)}")
35print(f"2^8 = {power_of_2(8)}")36print(f"10^3 = {power_of_10(3)}")output2^8 = 256error ← functools.partial(⟨function format_message C⟩, '[ERROR] ', suffix='')
35print(f"2^8 = {power_of_2(8)}")36print(f"10^3 = {power_of_10(3)}")3738# String formatting39print("\nString formatting:")4041def format_message(prefix, message, suffix):42 return f"{prefix}{message}{suffix}"4344# Create specialized formatters45error→ functools.partial(⟨function format_message C⟩, '[ERROR] ', suffix='') = partial(format_message⟨function format_message C⟩, "[ERROR] ", suffix="")46warning→ functools.partial(⟨function format_message C⟩, '[WARN] ', suffix='') = partial(format_message⟨function format_message C⟩, "[WARN] ", suffix="")47info→ functools.partial(⟨function format_message C⟩, '[INFO] ', suffix='') = partial(format_message⟨function format_message C⟩, "[INFO] ", suffix="")4849print(error("File not found"))50print(warning("Deprecated function"))output10^3 = 1000 String formatting:def format_message(prefix, message, suffix):
pass 1 of 341def format_message(prefix[ERROR] , messageFile not found, suffix(empty)):42 return f"{prefix[ERROR] }{messageFile not found}{suffix(empty)}"All 3 passes — pass 1 is the card above pass prefixmessage1 [ERROR] File not found 2 [WARN] Deprecated function 3 [INFO] Process started print(error("File not found"))
49print(error("File not found"))50print(warning("Deprecated function"))51print(info("Process started"))output[ERROR] File not foundprint(warning("Deprecated function"))
49print(error("File not found"))50print(warning("Deprecated function"))51print(info("Process started"))output[WARN] Deprecated functionstudents ← [{'name': 'Alice', 'age': 20, 'grade': 85}, {'name': 'Bob', 'age': 22, 'grade': 92}, {'name': 'Charlie', 'age': 21, 'grade': 78}]
50print(warning("Deprecated function"))51print(info("Process started"))5253# Sorting with partial54print("\nSorting with partial:")5556# Sort by custom key57students→ [{'name': 'Alice', 'age': 20, 'grade': 85}, {'name': 'Bob', 'age': 22, 'grade': 92}, {'name': 'Charlie', 'age': 21, 'grade': 78}] = [58 {'name': 'Alice', 'age': 20, 'grade': 85},59 {'name': 'Bob', 'age': 22, 'grade': 92},60 {'name': 'Charlie', 'age': 21, 'grade': 78}61]6263from operator import itemgetter6465# Create reusable key functions66by_name→ functools.partial(<built-in function sorted>, key=operator.itemgetter('name')) = partial(sorted, key=itemgetter('name'))67by_age→ functools.partial(<built-in function sorted>, key=operator.itemgetter('age')) = partial(sorted, key=itemgetter('age'))68by_grade→ functools.partial(<built-in function sorted>, key=operator.itemgetter('grade')) = partial(sorted, key=itemgetter('grade'))6970print("By name:")71for s in by_name(students):output[INFO] Process started Sorting with partial: By name:for s in by_name(students):
pass 1 of 370print("By name:")71for s{'name': 'Alice', 'age': 20, 'grade': 85} in by_name(students[{'name': 'Alice', 'age': 20, 'grade': 85}, {'name': 'Bob', 'age': 22, 'grade': 92}, {'name': 'Charlie', 'age': 21, 'grade': 78}]):72 print(f" {s['name']Alice}: {s['grade']85}")output Alice: 85All 3 passes — pass 1 is the card above pass ss[’name’]s[’grade’]1 {'name': 'Alice', 'age': 20, 'grade': 85} Alice 85 2 {'name': 'Bob', 'age': 22, 'grade': 92} Bob 92 3 {'name': 'Charlie', 'age': 21, 'grade': 78} Charlie 78 print("By grade:")
74print("By grade:")75for s in by_grade(students):outputBy grade:for s in by_grade(students):
pass 1 of 374print("By grade:")75for s{'name': 'Charlie', 'age': 21, 'grade': 78} in by_grade(students[{'name': 'Alice', 'age': 20, 'grade': 85}, {'name': 'Bob', 'age': 22, 'grade': 92}, {'name': 'Charlie', 'age': 21, 'grade': 78}]):76 print(f" {s['name']Charlie}: {s['grade']78}")output Charlie: 78All 3 passes — pass 1 is the card above pass ss[’name’]s[’grade’]1 {'name': 'Charlie', 'age': 21, 'grade': 78} Charlie 78 2 {'name': 'Alice', 'age': 20, 'grade': 85} Alice 85 3 {'name': 'Bob', 'age': 22, 'grade': 92} Bob 92 read_text ← functools.partial(⟨function read_file D⟩, mode='r', encoding='utf-8')
78# File operations79print("\nFile operations:")8081def read_file(filename, mode='r', encoding='utf-8'):82 """Simulate file reading."""83 return f"Reading {filename} (mode={mode}, encoding={encoding})"8485# Create specialized readers86read_text→ functools.partial(⟨function read_file D⟩, mode='r', encoding='utf-8') = partial(read_file⟨function read_file D⟩, mode='r', encoding='utf-8')87read_binary→ functools.partial(⟨function read_file D⟩, mode='rb', encoding=None) = partial(read_file⟨function read_file D⟩, mode='rb', encoding=None)88read_json→ functools.partial(⟨function read_file D⟩, mode='r', encoding='utf-8') = partial(read_file⟨function read_file D⟩, mode='r', encoding='utf-8')8990print(read_text('data.txt'))91print(read_binary('image.png'))output File operations:def read_file(filename, mode='r', encoding='utf-8'):
pass 1 of 281def read_file(filenamedata.txt, moder='r', encodingutf-8='utf-8'):82 """Simulate file reading."""83 return f"Reading {filenamedata.txt} (mode={moder}, encoding={encodingutf-8})"print(read_text('data.txt'))
90print(read_text('data.txt'))91print(read_binary('image.png'))outputReading data.txt (mode=r, encoding=utf-8)def read_file(filename, mode='r', encoding='utf-8'):
pass 2 of 281def read_file(filenameimage.png, moderb='r', encodingNone='utf-8'):82 """Simulate file reading."""83 return f"Reading {filenameimage.png} (mode={moderb}, encoding={encodingNone})"db_log ← functools.partial(⟨function log E⟩, component='Database')
90print(read_text('data.txt'))91print(read_binary('image.png'))9293# Logging94print("\nLogging:")9596def log(level, component, message):97 print(f"[{level}] {component}: {message}")9899# Create component-specific loggers100db_log→ functools.partial(⟨function log E⟩, component='Database') = partial(log⟨function log E⟩, component='Database')101api_log→ functools.partial(⟨function log E⟩, component='API') = partial(log⟨function log E⟩, component='API')102cache_log→ functools.partial(⟨function log E⟩, component='Cache') = partial(log⟨function log E⟩, component='Cache')103104db_log(level='INFO', message='Connected to PostgreSQL')105api_log(level='WARN', message='Rate limit approaching')outputReading image.png (mode=rb, encoding=None) Logging:def log(level, component, message):
pass 1 of 396def log(levelINFO, componentDatabase, messageConnected to PostgreSQL):97 print(f"[{levelINFO}] {componentDatabase}: {messageConnected to PostgreSQL}")output[INFO] Database: Connected to PostgreSQLAll 3 passes — pass 1 is the card above pass levelcomponentmessage1 INFO Database Connected to PostgreSQL 2 WARN API Rate limit approaching 3 ERROR Cache Redis connection failed db_log(level='INFO', message='Connected to PostgreSQL')
104db_log(level='INFO', message='Connected to PostgreSQL')105api_log(level='WARN', message='Rate limit approaching')106cache_log(level='ERROR', message='Redis connection failed')api_log(level='WARN', message='Rate limit approaching')
104db_log(level='INFO', message='Connected to PostgreSQL')105api_log(level='WARN', message='Rate limit approaching')106cache_log(level='ERROR', message='Redis connection failed')numbers ← [1, 2, 3, 4, 5], add_10 ← functools.partial(⟨function add F⟩, 10)
105api_log(level='WARN', message='Rate limit approaching')106cache_log(level='ERROR', message='Redis connection failed')107108# Map with partial109print("\nMap with partial:")110111def add(x, y):112 return x + y113114# Add 10 to each number115numbers→ [1, 2, 3, 4, 5] = [1, 2, 3, 4, 5]116add_10→ functools.partial(⟨function add F⟩, 10) = partial(add⟨function add F⟩, 10)117result = list(map(add_10functools.partial(⟨function add F⟩, 10), numbers[1, 2, 3, 4, 5]))output Map with partial:def add(x, y):
pass 1 of 5111def add(x10, y1):112 return x10 + y1All 5 passes — pass 1 is the card above pass y1 1 2 2 3 3 4 4 5 5 result ← [11, 12, 13, 14, 15], values ← [25, 60, 45, 80, 30, 95]
116add_10 = partial(add, 10)117result→ [11, 12, 13, 14, 15] = list(map(add_10functools.partial(⟨function add F⟩, 10), numbers[1, 2, 3, 4, 5]))118119print(f"Original: {numbers[1, 2, 3, 4, 5]}")120print(f"Add 10: {result[11, 12, 13, 14, 15]}")121122# Filter with partial123print("\nFilter with partial:")124125def greater_than(threshold, value):126 return value > threshold127128# Filter values > 50129values→ [25, 60, 45, 80, 30, 95] = [25, 60, 45, 80, 30, 95]130above_50→ functools.partial(⟨function greater_than G⟩, 50) = partial(greater_than⟨function greater_than G⟩, 50)131filtered = list(filter(above_50functools.partial(⟨function greater_than G⟩, 50), values[25, 60, 45, 80, 30, 95]))outputOriginal: [1, 2, 3, 4, 5] Add 10: [11, 12, 13, 14, 15] Filter with partial:def greater_than(threshold, value):
pass 1 of 6125def greater_than(threshold50, value25):126 return value25 > threshold50All 6 passes — pass 1 is the card above pass value1 25 2 60 3 45 4 80 5 30 6 95 filtered ← [60, 80, 95], process_positive ← functools.partial(⟨function process_data H⟩, validator=⟨function is_positive I⟩, transformer=⟨function square J⟩)
130above_50 = partial(greater_than, 50)131filtered→ [60, 80, 95] = list(filter(above_50functools.partial(⟨function greater_than G⟩, 50), values[25, 60, 45, 80, 30, 95]))132133print(f"Values: {values[25, 60, 45, 80, 30, 95]}")134print(f"Above 50: {filtered[60, 80, 95]}")135136# Callback functions137print("\nCallback functions:")138139def process_data(data, validator, transformer):140 if validator(data):141 return transformer(data)142 return None143144def is_positive(x):145 return x > 0146147def is_even(x):148 return x % 2 == 0149150def square(x):151 return x * x152153# Create specialized processors154process_positive→ functools.partial(⟨function process_data H⟩, validator=⟨function is_positive I⟩, transformer=⟨function square J⟩) = partial(process_data⟨function process_data H⟩, validator=is_positive⟨function is_positive I⟩, transformer=square⟨function square J⟩)155process_even→ functools.partial(⟨function process_data H⟩, validator=⟨function is_even K⟩, transformer=⟨function square J⟩) = partial(process_data⟨function process_data H⟩, validator=is_even⟨function is_even K⟩, transformer=square⟨function square J⟩)156157print(f"Process positive 5: {process_positive(5)}")158print(f"Process positive -3: {process_positive(-3)}")outputValues: [25, 60, 45, 80, 30, 95] Above 50: [60, 80, 95] Callback functions:def process_data(data, validator, transformer):
pass 1 of 4139def process_data(data5, validator⟨function is_positive I⟩, transformer⟨function square J⟩):140 if validator(data):141 return transformer(data)All 4 passes — pass 1 is the card above pass datavalidatorx1 5 ⟨function is_positive I⟩ 5 2 -3 ⟨function is_positive I⟩ -3 3 4 ⟨function is_even K⟩ 4 4 3 ⟨function is_even K⟩ 3 def is_positive(x):
pass 1 of 2144def is_positive(x5):145 return x5 > 0if validator(data):
pass 1 of 2139def process_data(data, validator, transformer):140 if validator(data5):141 return transformer(data5)142 return Nonedef square(x):
pass 1 of 2150def square(x5):151 return x5 * xprint(f"Process positive 5: {process_positive(5)}")
157print(f"Process positive 5: {process_positive(5)}")158print(f"Process positive -3: {process_positive(-3)}")159print(f"Process even 4: {process_even(4)}")outputProcess positive 5: 25def is_positive(x):
pass 2 of 2144def is_positive(x-3):145 return x-3 > 0return None
141 return transformer(data)142return Noneprint(f"Process positive -3: {process_positive(-3)}")
157print(f"Process positive 5: {process_positive(5)}")158print(f"Process positive -3: {process_positive(-3)}")159print(f"Process even 4: {process_even(4)}")160print(f"Process even 3: {process_even(3)}")outputProcess positive -3: Nonedef is_even(x):
pass 1 of 2147def is_even(x4):148 return x4 % 2 == 0if validator(data):
pass 2 of 2139def process_data(data, validator, transformer):140 if validator(data4):141 return transformer(data4)142 return Nonedef square(x):
pass 2 of 2150def square(x4):151 return x4 * xprint(f"Process even 4: {process_even(4)}")
158print(f"Process positive -3: {process_positive(-3)}")159print(f"Process even 4: {process_even(4)}")160print(f"Process even 3: {process_even(3)}")outputProcess even 4: 16def is_even(x):
pass 2 of 2147def is_even(x3):148 return x3 % 2 == 0return None
141 return transformer(data)142return Nonegreet ← functools.partial(⟨function format_message C⟩, 'Hello, ')
159print(f"Process even 4: {process_even(4)}")160print(f"Process even 3: {process_even(3)}")161162# Partial attributes163print("\nPartial attributes:")164165greet→ functools.partial(⟨function format_message C⟩, 'Hello, ') = partial(format_message⟨function format_message C⟩, "Hello, ")166167print(f"Function: {greet.func⟨function format_message C⟩}")168print(f"Args: {greet.args('Hello, ',)}")169print(f"Keywords: {greet.keywords{}}")outputProcess even 3: None Partial attributes: Function: ⟨function format_message C⟩ Args: ('Hello, ',) Keywords: {}
partial()
Creates a new function with some arguments pre-filled, reducing repetition and creating more specific functions from general ones.
Single Dispatch
Function overloading based on argument type:
dispatch.py
Replay: real traced execution (multi-file project)
# functools.singledispatch examples
from functools import singledispatch
from decimal import Decimal
# Basic singledispatch
print("Basic singledispatch:")
@singledispatch
def process(arg):
"""Default implementation."""
print(f"Processing {type(arg).__name__}: {arg}")
@process.register(int)
def _(arg):
print(f"Integer: {arg} (squared: {arg**2})")
@process.register(str)
def _(arg):
print(f"String: '{arg}' (length: {len(arg)})")
@process.register(list)
def _(arg):
print(f"List: {arg} (sum: {sum(arg)})")
# Call with different types
process(10)
process("hello")
process([1, 2, 3, 4, 5])
process(3.14) # Uses default
# Format function
print("\nFormat function:")
@singledispatch
def format_value(val):
"""Default formatter."""
return str(val)
@format_value.register(int)
def _(val):
return f"{val:,}"
@format_value.register(float)
def _(val):
return f"{val:.2f}"
@format_value.register(bool)
def _(val):
return "Yes" if val else "No"
@format_value.register(list)
def _(val):
return f"[{len(val)} items]"
print(f"Integer: {format_value(1000000)}")
print(f"Float: {format_value(3.14159)}")
print(f"Bool: {format_value(True)}")
print(f"List: {format_value([1, 2, 3, 4, 5])}")
# Serialize function
print("\nSerialize function:")
@singledispatch
def serialize(obj):
"""Default serialization."""
raise NotImplementedError(f"Cannot serialize {type(obj)}")
@serialize.register(int)
@serialize.register(float)
@serialize.register(str)
def _(obj):
return obj
@serialize.register(list)
def _(obj):
return [serialize(item) for item in obj]
@serialize.register(dict)
def _(obj):
return {key: serialize(value) for key, value in obj.items()}
data = {
'name': 'Alice',
'age': 30,
'scores': [85, 92, 78],
'active': True
}
try:
result = serialize(data)
print(f"Serialized: {result}")
except NotImplementedError as e:
print(f"Error: {e}")
# Area calculation
print("\nArea calculation:")
@singledispatch
def area(shape):
"""Calculate area of shape."""
raise NotImplementedError(f"Unknown shape: {type(shape)}")
class Circle:
def __init__(self, radius):
self.radius = radius
class Rectangle:
def __init__(self, width, height):
self.width = width
self.height = height
class Triangle:
def __init__(self, base, height):
self.base = base
self.height = height
@area.register(Circle)
def _(shape):
import math
return math.pi * shape.radius ** 2
@area.register(Rectangle)
def _(shape):
return shape.width * shape.height
@area.register(Triangle)
def _(shape):
return 0.5 * shape.base * shape.height
# Calculate areas
circle = Circle(5)
rectangle = Rectangle(4, 6)
triangle = Triangle(3, 8)
print(f"Circle area: {area(circle):.2f}")
print(f"Rectangle area: {area(rectangle):.2f}")
print(f"Triangle area: {area(triangle):.2f}")
# Type conversion
print("\nType conversion:")
@singledispatch
def to_string(val):
"""Convert to string."""
return str(val)
@to_string.register(int)
def _(val):
return f"Integer: {val}"
@to_string.register(float)
def _(val):
return f"Float: {val:.4f}"
@to_string.register(Decimal)
def _(val):
return f"Decimal: {val}"
@to_string.register(list)
def _(val):
return f"List with {len(val)} elements"
print(to_string(42))
print(to_string(3.14159))
print(to_string(Decimal('10.50')))
print(to_string([1, 2, 3]))
# HTML rendering
print("\nHTML rendering:")
@singledispatch
def to_html(data):
"""Render data as HTML."""
return f"<span>{data}</span>"
@to_html.register(int)
@to_html.register(float)
def _(data):
return f"<strong>{data}</strong>"
@to_html.register(str)
def _(data):
return f"<p>{data}</p>"
@to_html.register(list)
def _(data):
items = ''.join(f"<li>{to_html(item)}</li>" for item in data)
return f"<ul>{items}</ul>"
@to_html.register(dict)
def _(data):
rows = ''.join(
f"<tr><td>{key}</td><td>{to_html(value)}</td></tr>"
for key, value in data.items()
)
return f"<table>{rows}</table>"
print(to_html("Hello"))
print(to_html(42))
print(to_html([1, 2, 3]))
# Validator
print("\nValidator:")
@singledispatch
def validate(val):
"""Validate value."""
return True
@validate.register(str)
def _(val):
return len(val) > 0
@validate.register(int)
def _(val):
return val >= 0
@validate.register(list)
def _(val):
return len(val) > 0 and all(validate(item) for item in val)
print(f"Validate 'hello': {validate('hello')}")
print(f"Validate '': {validate('')}")
print(f"Validate 10: {validate(10)}")
print(f"Validate -5: {validate(-5)}")
print(f"Validate [1, 2]: {validate([1, 2])}")
# Type dispatch info
print("\nType dispatch info:")
@singledispatch
def demo(arg):
return "default"
@demo.register(int)
def _(arg):
return "int"
@demo.register(str)
def _(arg):
return "str"
# Check registered types
print(f"Registry: {demo.registry.keys()}")
print(f"Dispatch(int): {demo.dispatch(int)}")
print(f"Dispatch(str): {demo.dispatch(str)}")
print("Basic singledispatch:")
6# Basic singledispatch7print("Basic singledispatch:")89@singledispatch10def process(arg):11 """Default implementation."""12 print(f"Processing {type(arg).__name__}: {arg}")1314@process.register(int)15def _(arg):16 print(f"Integer: {arg} (squared: {arg**2})")1718@process.register(str)19def _(arg):20 print(f"String: '{arg}' (length: {len(arg)})")2122@process.register(list)23def _(arg):24 print(f"List: {arg} (sum: {sum(arg)})")2526# Call with different types27process(10)28process("hello")outputBasic singledispatch:def _(arg):
14@process.register(int)15def _(arg10):16 print(f"Integer: {arg10} (squared: {arg**2})")outputInteger: 10 (squared: 100)process(10)
26# Call with different types27process(10)28process("hello")29process([1, 2, 3, 4, 5])def _(arg):
18@process.register(str)19def _(arghello):20 print(f"String: '{arghello}' (length: {len(arg)})")outputString: 'hello' (length: 5)process("hello")
27process(10)28process("hello")29process([1, 2, 3, 4, 5])30process(3.14) # Uses defaultdef _(arg):
22@process.register(list)23def _(arg[1, 2, 3, 4, 5]):24 print(f"List: {arg[1, 2, 3, 4, 5]} (sum: {sum(arg)})")outputList: [1, 2, 3, 4, 5] (sum: 15)process([1, 2, 3, 4, 5])
28process("hello")29process([1, 2, 3, 4, 5])30process(3.14) # Uses defaultdef process(arg):
9@singledispatch10def process(arg3.14):11 """Default implementation."""12 print(f"Processing {type(arg3.14).__name__}: {arg}")outputProcessing float: 3.14process(3.14) # Uses default
29process([1, 2, 3, 4, 5])30process(3.14) # Uses default3132# Format function33print("\nFormat function:")3435@singledispatch36def format_value(val):37 """Default formatter."""38 return str(val)3940@format_value.register(int)41def _(val):42 return f"{val:,}"4344@format_value.register(float)45def _(val):46 return f"{val:.2f}"4748@format_value.register(bool)49def _(val):50 return "Yes" if val else "No"5152@format_value.register(list)53def _(val):54 return f"[{len(val)} items]"5556print(f"Integer: {format_value(1000000)}")57print(f"Float: {format_value(3.14159)}")output Format function:def _(val):
40@format_value.register(int)41def _(val1000000):42 return f"{val1000000:,}"print(f"Integer: {format_value(1000000)}")
56print(f"Integer: {format_value(1000000)}")57print(f"Float: {format_value(3.14159)}")58print(f"Bool: {format_value(True)}")outputInteger: 1,000,000def _(val):
44@format_value.register(float)45def _(val3.14159):46 return f"{val3.14159:.2f}"print(f"Float: {format_value(3.14159)}")
56print(f"Integer: {format_value(1000000)}")57print(f"Float: {format_value(3.14159)}")58print(f"Bool: {format_value(True)}")59print(f"List: {format_value([1, 2, 3, 4, 5])}")outputFloat: 3.14def _(val):
48@format_value.register(bool)49def _(valTrue):50 return "Yes" if valTrue else "No"print(f"Bool: {format_value(True)}")
57print(f"Float: {format_value(3.14159)}")58print(f"Bool: {format_value(True)}")59print(f"List: {format_value([1, 2, 3, 4, 5])}")outputBool: Yesdef _(val):
52@format_value.register(list)53def _(val[1, 2, 3, 4, 5]):54 return f"[{len(val[1, 2, 3, 4, 5])} items]"data ← {'name': 'Alice', 'age': 30, 'scores': [85, 92, 78], 'active': True}
58print(f"Bool: {format_value(True)}")59print(f"List: {format_value([1, 2, 3, 4, 5])}")6061# Serialize function62print("\nSerialize function:")6364@singledispatch65def serialize(obj):66 """Default serialization."""67 raise NotImplementedError(f"Cannot serialize {type(obj)}")6869@serialize.register(int)70@serialize.register(float)71@serialize.register(str)72def _(obj):73 return obj7475@serialize.register(list)76def _(obj):77 return [serialize(item) for item in obj]7879@serialize.register(dict)80def _(obj):81 return {key: serialize(value) for key, value in obj.items()}8283data→ {'name': 'Alice', 'age': 30, 'scores': [85, 92, 78], 'active': True} = {84 'name': 'Alice',85 'age': 30,86 'scores': [85, 92, 78],87 'active': True88}outputList: [5 items] Serialize function:try:
90try:91 result = serialize(data{'name': 'Alice', 'age': 30, 'scores': [85, 92, 78], 'active': True})92 print(f"Serialized: {result}")def _(obj):
79@serialize.register(dict)80def _(obj{'name': 'Alice', 'age': 30, 'scores': [85, 92, 78], 'active': True}):81 return {key(empty): serialize(value(empty)) for key, value in obj{'name': 'Alice', 'age': 30, 'scores': [85, 92, 78], 'active': True}.items()}def _(obj):
pass 1 of 671@serialize.register(str)72def _(objAlice):73 return objAliceAll 6 passes — pass 1 is the card above pass obj1 Alice 2 30 3 85 4 92 5 78 6 True def _(obj):
75@serialize.register(list)76def _(obj[85, 92, 78]):77 return [serialize(item) for item in obj[85, 92, 78]]result ← {'name': 'Alice', 'age': 30, 'scores': [85, 92, 78], 'active': True}
90try:91 result→ {'name': 'Alice', 'age': 30, 'scores': [85, 92, 78], 'active': True} = serialize(data{'name': 'Alice', 'age': 30, 'scores': [85, 92, 78], 'active': True})92 print(f"Serialized: {result{'name': 'Alice', 'age': 30, 'scores': [85, 92, 78], 'active': True}}")93except NotImplementedError as e:outputSerialized: {'name': 'Alice', 'age': 30, 'scores': [85, 92, 78], 'active': True}print(" Area calculation:")
96# Area calculation97print("\nArea calculation:")9899@singledispatch100def area(shape):101 """Calculate area of shape."""102 raise NotImplementedError(f"Unknown shape: {type(shape)}")103104class Circle:105 def __init__(self, radius):106 self.radius = radius107108class Rectangle:109 def __init__(self, width, height):110 self.width = width111 self.height = height112113class Triangle:114 def __init__(self, base, height):115 self.base = base116 self.height = height117118@area.register(Circle)119def _(shape):120 import math121 return math.pi * shape.radius ** 2122123@area.register(Rectangle)124def _(shape):125 return shape.width * shape.height126127@area.register(Triangle)128def _(shape):129 return 0.5 * shape.base * shape.height130131# Calculate areas132circle = Circle(5)133rectangle = Rectangle(4, 6)output Area calculation:self.radius ← 5
104class Circle:105 def __init__(self⟨Circle A⟩, radius5):106 self.radius→ 5 = radius5circle ← ⟨Circle A⟩
131# Calculate areas132circle→ ⟨Circle A⟩ = Circle(5)133rectangle = Rectangle(4, 6)134triangle = Triangle(3, 8)self.width ← 4, self.height ← 6
108class Rectangle:109 def __init__(self⟨Rectangle B⟩, width4, height6):110 self.width→ 4 = width4111 self.height→ 6 = height6rectangle ← ⟨Rectangle B⟩
132circle = Circle(5)133rectangle→ ⟨Rectangle B⟩ = Rectangle(4, 6)134triangle = Triangle(3, 8)self.base ← 3, self.height ← 8
113class Triangle:114 def __init__(self⟨Triangle C⟩, base3, height8):115 self.base→ 3 = base3116 self.height→ 8 = height8triangle ← ⟨Triangle C⟩
133rectangle = Rectangle(4, 6)134triangle→ ⟨Triangle C⟩ = Triangle(3, 8)135136print(f"Circle area: {area(circle⟨Circle A⟩):.2f}")137print(f"Rectangle area: {area(rectangle):.2f}")def _(shape):
118@area.register(Circle)119def _(shape⟨Circle A⟩):120 import math121 return math.pi3.141592653589793 * shape.radius5 ** 2print(f"Circle area: {area(circle):.2f}")
136print(f"Circle area: {area(circle⟨Circle A⟩):.2f}")137print(f"Rectangle area: {area(rectangle⟨Rectangle B⟩):.2f}")138print(f"Triangle area: {area(triangle):.2f}")outputCircle area: 78.54def _(shape):
123@area.register(Rectangle)124def _(shape⟨Rectangle B⟩):125 return shape.width4 * shape.height6print(f"Rectangle area: {area(rectangle):.2f}")
136print(f"Circle area: {area(circle):.2f}")137print(f"Rectangle area: {area(rectangle⟨Rectangle B⟩):.2f}")138print(f"Triangle area: {area(triangle⟨Triangle C⟩):.2f}")outputRectangle area: 24.00def _(shape):
127@area.register(Triangle)128def _(shape⟨Triangle C⟩):129 return 0.5 * shape.base3 * shape.height8print(f"Triangle area: {area(triangle):.2f}")
137print(f"Rectangle area: {area(rectangle):.2f}")138print(f"Triangle area: {area(triangle⟨Triangle C⟩):.2f}")139140# Type conversion141print("\nType conversion:")142143@singledispatch144def to_string(val):145 """Convert to string."""146 return str(val)147148@to_string.register(int)149def _(val):150 return f"Integer: {val}"151152@to_string.register(float)153def _(val):154 return f"Float: {val:.4f}"155156@to_string.register(Decimal)157def _(val):158 return f"Decimal: {val}"159160@to_string.register(list)161def _(val):162 return f"List with {len(val)} elements"163164print(to_string(42))165print(to_string(3.14159))outputTriangle area: 12.00 Type conversion:def _(val):
148@to_string.register(int)149def _(val42):150 return f"Integer: {val42}"print(to_string(42))
164print(to_string(42))165print(to_string(3.14159))166print(to_string(Decimal('10.50')))outputInteger: 42def _(val):
152@to_string.register(float)153def _(val3.14159):154 return f"Float: {val3.14159:.4f}"print(to_string(3.14159))
164print(to_string(42))165print(to_string(3.14159))166print(to_string(Decimal('10.50')))167print(to_string([1, 2, 3]))outputFloat: 3.1416def _(val):
156@to_string.register(Decimal)157def _(val10.50):158 return f"Decimal: {val10.50}"print(to_string(Decimal('10.50')))
165print(to_string(3.14159))166print(to_string(Decimal('10.50')))167print(to_string([1, 2, 3]))outputDecimal: 10.50def _(val):
160@to_string.register(list)161def _(val[1, 2, 3]):162 return f"List with {len(val[1, 2, 3])} elements"print(to_string([1, 2, 3]))
166print(to_string(Decimal('10.50')))167print(to_string([1, 2, 3]))168169# HTML rendering170print("\nHTML rendering:")171172@singledispatch173def to_html(data):174 """Render data as HTML."""175 return f"<span>{data}</span>"176177@to_html.register(int)178@to_html.register(float)179def _(data):180 return f"<strong>{data}</strong>"181182@to_html.register(str)183def _(data):184 return f"<p>{data}</p>"185186@to_html.register(list)187def _(data):188 items = ''.join(f"<li>{to_html(item)}</li>" for item in data)189 return f"<ul>{items}</ul>"190191@to_html.register(dict)192def _(data):193 rows = ''.join(194 f"<tr><td>{key}</td><td>{to_html(value)}</td></tr>"195 for key, value in data.items()196 )197 return f"<table>{rows}</table>"198199print(to_html("Hello"))200print(to_html(42))outputList with 3 elements HTML rendering:def _(data):
182@to_html.register(str)183def _(dataHello):184 return f"<p>{dataHello}</p>"print(to_html("Hello"))
199print(to_html("Hello"))200print(to_html(42))201print(to_html([1, 2, 3]))output<p>Hello</p>def _(data):
pass 1 of 4178@to_html.register(float)179def _(data42):180 return f"<strong>{data42}</strong>"All 4 passes — pass 1 is the card above pass data1 42 2 1 3 2 4 3 print(to_html(42))
199print(to_html("Hello"))200print(to_html(42))201print(to_html([1, 2, 3]))output<strong>42</strong>def _(data):
186@to_html.register(list)187def _(data[1, 2, 3]):188 items = ''.join(f"<li>{to_html(item)}</li>" for item in data[1, 2, 3])189 return f"<ul>{items}</ul>"items ← <li><strong>1</strong></li><li><strong>2</strong></li><li><strong>3</strong></li>
187def _(data):188 items→ <li><strong>1</strong></li><li><strong>2</strong></li><li><strong>3</strong></li> = ''.join(f"<li>{to_html(item)}</li>" for item in data[1, 2, 3])189 return f"<ul>{items<li><strong>1</strong></li><li><strong>2</strong></li><li><strong>3</strong></li>}</ul>"print(to_html([1, 2, 3]))
200print(to_html(42))201print(to_html([1, 2, 3]))202203# Validator204print("\nValidator:")205206@singledispatch207def validate(val):208 """Validate value."""209 return True210211@validate.register(str)212def _(val):213 return len(val) > 0214215@validate.register(int)216def _(val):217 return val >= 0218219@validate.register(list)220def _(val):221 return len(val) > 0 and all(validate(item) for item in val)222223print(f"Validate 'hello': {validate('hello')}")224print(f"Validate '': {validate('')}")output<ul><li><strong>1</strong></li><li><strong>2</strong></li><li><strong>3</strong></li></ul> Validator:def _(val):
pass 1 of 2211@validate.register(str)212def _(valhello):213 return len(valhello) > 0print(f"Validate 'hello': {validate('hello')}")
223print(f"Validate 'hello': {validate('hello')}")224print(f"Validate '': {validate('')}")225print(f"Validate 10: {validate(10)}")outputValidate 'hello': Truedef _(val):
pass 2 of 2211@validate.register(str)212def _(val(empty)):213 return len(val(empty)) > 0print(f"Validate '': {validate('')}")
223print(f"Validate 'hello': {validate('hello')}")224print(f"Validate '': {validate('')}")225print(f"Validate 10: {validate(10)}")226print(f"Validate -5: {validate(-5)}")outputValidate '': Falsedef _(val):
pass 1 of 4215@validate.register(int)216def _(val10):217 return val10 >= 0All 4 passes — pass 1 is the card above pass val1 10 2 -5 3 1 4 2 print(f"Validate 10: {validate(10)}")
224print(f"Validate '': {validate('')}")225print(f"Validate 10: {validate(10)}")226print(f"Validate -5: {validate(-5)}")227print(f"Validate [1, 2]: {validate([1, 2])}")outputValidate 10: Trueprint(f"Validate -5: {validate(-5)}")
225print(f"Validate 10: {validate(10)}")226print(f"Validate -5: {validate(-5)}")227print(f"Validate [1, 2]: {validate([1, 2])}")outputValidate -5: Falsedef _(val):
219@validate.register(list)220def _(val[1, 2]):221 return len(val[1, 2]) > 0 and all(validate(item) for item in val)print(f"Registry: {demo.registry.keys()}")
226print(f"Validate -5: {validate(-5)}")227print(f"Validate [1, 2]: {validate([1, 2])}")228229# Type dispatch info230print("\nType dispatch info:")231232@singledispatch233def demo(arg):234 return "default"235236@demo.register(int)237def _(arg):238 return "int"239240@demo.register(str)241def _(arg):242 return "str"243244# Check registered types245print(f"Registry: {demo.registry{<class 'object'>: ⟨function demo D⟩, <class 'int'>: ⟨function _ E⟩, <class 'str'>: ⟨function _ F⟩}.keys()}")246print(f"Dispatch(int): {demo⟨function demo G⟩.dispatch(int)}")247print(f"Dispatch(str): {demo⟨function demo G⟩.dispatch(str)}")outputValidate [1, 2]: True Type dispatch info: Registry: dict_keys([<class 'object'>, <class 'int'>, <class 'str'>]) Dispatch(int): ⟨function _ E⟩ Dispatch(str): ⟨function _ F⟩
Total Ordering
Generate comparison methods automatically:
ordering.py
Replay: real traced execution (multi-file project)
# functools.total_ordering examples
from functools import total_ordering
# Basic total_ordering
print("Basic total_ordering:")
@total_ordering
class Student:
def __init__(self, name, grade):
self.name = name
self.grade = grade
def __eq__(self, other):
return self.grade == other.grade
def __lt__(self, other):
return self.grade < other.grade
def __repr__(self):
return f"Student('{self.name}', {self.grade})"
# Create students
alice = Student("Alice", 85)
bob = Student("Bob", 92)
charlie = Student("Charlie", 85)
# All comparison operations work
print(f"alice < bob: {alice < bob}")
print(f"alice <= bob: {alice <= bob}")
print(f"alice > bob: {alice > bob}")
print(f"alice >= bob: {alice >= bob}")
print(f"alice == charlie: {alice == charlie}")
print(f"alice != bob: {alice != bob}")
# Sorting
print("\nSorting:")
students = [
Student("David", 78),
Student("Eve", 95),
Student("Frank", 82),
Student("Grace", 88)
]
print("Unsorted:")
for s in students:
print(f" {s}")
sorted_students = sorted(students)
print("Sorted by grade:")
for s in sorted_students:
print(f" {s}")
# Temperature class
print("\nTemperature class:")
@total_ordering
class Temperature:
def __init__(self, celsius):
self.celsius = celsius
def __eq__(self, other):
return self.celsius == other.celsius
def __lt__(self, other):
return self.celsius < other.celsius
def __repr__(self):
return f"{self.celsius}°C"
temps = [
Temperature(20),
Temperature(5),
Temperature(30),
Temperature(15)
]
print(f"Temperatures: {temps}")
print(f"Sorted: {sorted(temps)}")
print(f"Min: {min(temps)}")
print(f"Max: {max(temps)}")
# Version class
print("\nVersion class:")
@total_ordering
class Version:
def __init__(self, version_string):
self.parts = tuple(map(int, version_string.split('.')))
def __eq__(self, other):
return self.parts == other.parts
def __lt__(self, other):
return self.parts < other.parts
def __repr__(self):
return '.'.join(map(str, self.parts))
versions = [
Version("1.2.3"),
Version("1.10.0"),
Version("1.2.10"),
Version("2.0.0")
]
print(f"Versions: {versions}")
print(f"Sorted: {sorted(versions)}")
# Money class
print("\nMoney class:")
@total_ordering
class Money:
def __init__(self, amount, currency='USD'):
self.amount = amount
self.currency = currency
def __eq__(self, other):
if self.currency != other.currency:
raise ValueError("Cannot compare different currencies")
return self.amount == other.amount
def __lt__(self, other):
if self.currency != other.currency:
raise ValueError("Cannot compare different currencies")
return self.amount < other.amount
def __repr__(self):
return f"${self.amount:.2f} {self.currency}"
prices = [
Money(19.99),
Money(5.99),
Money(12.50),
Money(25.00)
]
print(f"Prices: {prices}")
print(f"Cheapest: {min(prices)}")
print(f"Most expensive: {max(prices)}")
# Date class
print("\nDate class:")
@total_ordering
class SimpleDate:
def __init__(self, year, month, day):
self.year = year
self.month = month
self.day = day
def __eq__(self, other):
return (self.year, self.month, self.day) == \
(other.year, other.month, other.day)
def __lt__(self, other):
return (self.year, self.month, self.day) < \
(other.year, other.month, other.day)
def __repr__(self):
return f"{self.year}-{self.month:02d}-{self.day:02d}"
dates = [
SimpleDate(2024, 5, 15),
SimpleDate(2023, 12, 1),
SimpleDate(2024, 1, 10),
SimpleDate(2024, 5, 1)
]
print(f"Dates: {dates}")
print(f"Sorted: {sorted(dates)}")
# Range checking
print("\nRange checking:")
@total_ordering
class Score:
def __init__(self, value):
self.value = value
def __eq__(self, other):
return self.value == other.value
def __lt__(self, other):
return self.value < other.value
def __repr__(self):
return f"Score({self.value})"
score = Score(75)
min_score = Score(60)
max_score = Score(100)
print(f"Score: {score}")
print(f"In range [60, 100]? {min_score <= score <= max_score}")
# Priority
print("\nPriority:")
@total_ordering
class Task:
PRIORITIES = {'low': 3, 'medium': 2, 'high': 1}
def __init__(self, name, priority):
self.name = name
self.priority = priority
def __eq__(self, other):
return self.PRIORITIES[self.priority] == \
self.PRIORITIES[other.priority]
def __lt__(self, other):
return self.PRIORITIES[self.priority] < \
self.PRIORITIES[other.priority]
def __repr__(self):
return f"Task('{self.name}', '{self.priority}')"
tasks = [
Task("Write docs", "low"),
Task("Fix bug", "high"),
Task("Review code", "medium"),
Task("Deploy", "high")
]
print("Tasks:")
for t in tasks:
print(f" {t}")
print("\nSorted by priority:")
for t in sorted(tasks):
print(f" {t}")
print("Basic total_ordering:")
5# Basic total_ordering6print("Basic total_ordering:")78@total_ordering9class Student:10 def __init__(self, name, grade):11 self.name = name12 self.grade = grade13 14 def __eq__(self, other):15 return self.grade == other.grade16 17 def __lt__(self, other):18 return self.grade < other.grade19 20 def __repr__(self):21 return f"Student('{self.name}', {self.grade})"2223# Create students24alice = Student("Alice", 85)25bob = Student("Bob", 92)outputBasic total_ordering:self.name ← Alice, self.grade ← 85
pass 1 of 79class Student:10 def __init__(self(empty), nameAlice, grade85):11 self.name→ Alice = nameAlice12 self.grade→ 85 = grade85All 7 passes — pass 1 is the card above pass namegradeself.nameself.grade1 Alice 85 Alice 85 2 Bob 92 Bob 92 3 Charlie 85 Charlie 85 4 David 78 David 78 5 Eve 95 Eve 95 6 Frank 82 Frank 82 7 Grace 88 Grace 88 alice ← Student('Alice', 85)
23# Create students24alice→ Student('Alice', 85) = Student("Alice", 85)25bob = Student("Bob", 92)26charlie = Student("Charlie", 85)bob ← Student('Bob', 92)
24alice = Student("Alice", 85)25bob→ Student('Bob', 92) = Student("Bob", 92)26charlie = Student("Charlie", 85)charlie ← Student('Charlie', 85)
25bob = Student("Bob", 92)26charlie→ Student('Charlie', 85) = Student("Charlie", 85)2728# All comparison operations work29print(f"alice < bob: {aliceStudent('Alice', 85) < bobStudent('Bob', 92)}")30print(f"alice <= bob: {alice <= bob}")def __lt__(self, other):
pass 1 of 1017def __lt__(selfStudent('Alice', 85), otherStudent('Bob', 92)):18 return self.grade85 < other.grade92All 10 passes — pass 1 is the card above pass selfotherself.gradeother.grade1 Student('Alice', 85) Student('Bob', 92) 85 92 2 Student('Alice', 85) Student('Bob', 92) 85 92 3 Student('Alice', 85) Student('Bob', 92) 85 92 4 Student('Alice', 85) Student('Bob', 92) 85 92 5 Student('Eve', 95) Student('David', 78) 95 78 6 Student('Frank', 82) Student('Eve', 95) 82 95 7 Student('Frank', 82) Student('Eve', 95) 82 95 8 Student('Frank', 82) Student('David', 78) 82 78 9 Student('Grace', 88) Student('Frank', 82) 88 82 10 Student('Grace', 88) Student('Eve', 95) 88 95 print(f"alice < bob: {alice < bob}")
28# All comparison operations work29print(f"alice < bob: {aliceStudent('Alice', 85) < bobStudent('Bob', 92)}")30print(f"alice <= bob: {aliceStudent('Alice', 85) <= bobStudent('Bob', 92)}")31print(f"alice > bob: {alice > bob}")outputalice < bob: Trueprint(f"alice <= bob: {alice <= bob}")
29print(f"alice < bob: {alice < bob}")30print(f"alice <= bob: {aliceStudent('Alice', 85) <= bobStudent('Bob', 92)}")31print(f"alice > bob: {aliceStudent('Alice', 85) > bobStudent('Bob', 92)}")32print(f"alice >= bob: {alice >= bob}")outputalice <= bob: Trueprint(f"alice > bob: {alice > bob}")
30print(f"alice <= bob: {alice <= bob}")31print(f"alice > bob: {aliceStudent('Alice', 85) > bobStudent('Bob', 92)}")32print(f"alice >= bob: {aliceStudent('Alice', 85) >= bobStudent('Bob', 92)}")33print(f"alice == charlie: {alice == charlie}")outputalice > bob: Falseprint(f"alice >= bob: {alice >= bob}")
31print(f"alice > bob: {alice > bob}")32print(f"alice >= bob: {aliceStudent('Alice', 85) >= bobStudent('Bob', 92)}")33print(f"alice == charlie: {aliceStudent('Alice', 85) == charlieStudent('Charlie', 85)}")34print(f"alice != bob: {alice != bob}")outputalice >= bob: Falsedef __eq__(self, other):
pass 1 of 214def __eq__(selfStudent('Alice', 85), otherStudent('Charlie', 85)):15 return self.grade85 == other.grade85print(f"alice == charlie: {alice == charlie}")
32print(f"alice >= bob: {alice >= bob}")33print(f"alice == charlie: {aliceStudent('Alice', 85) == charlieStudent('Charlie', 85)}")34print(f"alice != bob: {aliceStudent('Alice', 85) != bobStudent('Bob', 92)}")outputalice == charlie: Truedef __eq__(self, other):
pass 2 of 214def __eq__(selfStudent('Alice', 85), otherStudent('Bob', 92)):15 return self.grade85 == other.grade92print(f"alice != bob: {alice != bob}")
33print(f"alice == charlie: {alice == charlie}")34print(f"alice != bob: {aliceStudent('Alice', 85) != bobStudent('Bob', 92)}")3536# Sorting37print("\nSorting:")3839students = [40 Student("David", 78),41 Student("Eve", 95),42 Student("Frank", 82),43 Student("Grace", 88)44]outputalice != bob: True Sorting:students ← [Student('David', 78), Student('Eve', 95), Student('Frank', 82), Student('Grace', 88)]
39students→ [Student('David', 78), Student('Eve', 95), Student('Frank', 82), Student('Grace', 88)] = [40 Student("David", 78),41 Student("Eve", 95),42 Student("Frank", 82),43 Student("Grace", 88)44]4546print("Unsorted:")47for s in students:outputUnsorted:for s in students:
pass 1 of 446print("Unsorted:")47for sStudent('David', 78) in students[Student('David', 78), Student('Eve', 95), Student('Frank', 82), Student('Grace', 88)]:48 print(f" {sStudent('David', 78)}")output Student('David', 78)All 4 passes — pass 1 is the card above pass s1 Student('David', 78) 2 Student('Eve', 95) 3 Student('Frank', 82) 4 Student('Grace', 88) sorted_students = sorted(students)
50sorted_students = sorted(students[Student('David', 78), Student('Eve', 95), Student('Frank', 82), Student('Grace', 88)])sorted_students ← [Student('David', 78), Student('Frank', 82), Student('Grace', 88), Student('Eve', 95)]
50sorted_students→ [Student('David', 78), Student('Frank', 82), Student('Grace', 88), Student('Eve', 95)] = sorted(students[Student('David', 78), Student('Eve', 95), Student('Frank', 82), Student('Grace', 88)])5152print("Sorted by grade:")53for s in sorted_students:outputSorted by grade:for s in sorted_students:
pass 1 of 452print("Sorted by grade:")53for sStudent('David', 78) in sorted_students[Student('David', 78), Student('Frank', 82), Student('Grace', 88), Student('Eve', 95)]:54 print(f" {sStudent('David', 78)}")output Student('David', 78)All 4 passes — pass 1 is the card above pass s1 Student('David', 78) 2 Student('Frank', 82) 3 Student('Grace', 88) 4 Student('Eve', 95) print(" Temperature class:")
56# Temperature class57print("\nTemperature class:")5859@total_ordering60class Temperature:61 def __init__(self, celsius):62 self.celsius = celsius63 64 def __eq__(self, other):65 return self.celsius == other.celsius66 67 def __lt__(self, other):68 return self.celsius < other.celsius69 70 def __repr__(self):71 return f"{self.celsius}°C"7273temps = [74 Temperature(20),75 Temperature(5),76 Temperature(30),77 Temperature(15)78]output Temperature class:self.celsius ← 20
pass 1 of 460class Temperature:61 def __init__(self(empty), celsius20):62 self.celsius→ 20 = celsius20All 4 passes — pass 1 is the card above pass celsiusself.celsius1 20 20 2 5 5 3 30 30 4 15 15 temps ← [20°C, 5°C, 30°C, 15°C]
73temps→ [20°C, 5°C, 30°C, 15°C] = [74 Temperature(20),75 Temperature(5),76 Temperature(30),77 Temperature(15)78]7980print(f"Temperatures: {temps[20°C, 5°C, 30°C, 15°C]}")81print(f"Sorted: {sorted(temps[20°C, 5°C, 30°C, 15°C])}")82print(f"Min: {min(temps)}")outputTemperatures: [20°C, 5°C, 30°C, 15°C]def __lt__(self, other):
pass 1 of 1167def __lt__(self5°C, other20°C):68 return self.celsius5 < other.celsius20All 11 passes — pass 1 is the card above pass selfotherself.celsiusother.celsius1 5°C 20°C 5 20 2 30°C 5°C 30 5 3 30°C 20°C 30 20 4 15°C 20°C 15 20 5 15°C 5°C 15 5 6 5°C 20°C 5 20 7 30°C 5°C 30 5 8 15°C 5°C 15 5 9 5°C 20°C 5 20 10 30°C 20°C 30 20 11 15°C 30°C 15 30 print(f"Sorted: {sorted(temps)}")
80print(f"Temperatures: {temps}")81print(f"Sorted: {sorted(temps[20°C, 5°C, 30°C, 15°C])}")82print(f"Min: {min(temps[20°C, 5°C, 30°C, 15°C])}")83print(f"Max: {max(temps)}")outputSorted: [5°C, 15°C, 20°C, 30°C]print(f"Min: {min(temps)}")
81print(f"Sorted: {sorted(temps)}")82print(f"Min: {min(temps[20°C, 5°C, 30°C, 15°C])}")83print(f"Max: {max(temps[20°C, 5°C, 30°C, 15°C])}")outputMin: 5°Cdef __eq__(self, other):
64def __eq__(self30°C, other20°C):65 return self.celsius30 == other.celsius20print(f"Max: {max(temps)}")
82print(f"Min: {min(temps)}")83print(f"Max: {max(temps[20°C, 5°C, 30°C, 15°C])}")8485# Version class86print("\nVersion class:")8788@total_ordering89class Version:90 def __init__(self, version_string):91 self.parts = tuple(map(int, version_string.split('.')))92 93 def __eq__(self, other):94 return self.parts == other.parts95 96 def __lt__(self, other):97 return self.parts < other.parts98 99 def __repr__(self):100 return '.'.join(map(str, self.parts))101102versions = [103 Version("1.2.3"),104 Version("1.10.0"),105 Version("1.2.10"),106 Version("2.0.0")107]outputMax: 30°C Version class:self.parts ← (1, 2, 3)
pass 1 of 489class Version:90 def __init__(self(empty), version_string1.2.3):91 self.parts→ (1, 2, 3) = tuple(map(int, version_string1.2.3.split('.')))All 4 passes — pass 1 is the card above pass version_stringself.parts1 1.2.3 (1, 2, 3) 2 1.10.0 (1, 10, 0) 3 1.2.10 (1, 2, 10) 4 2.0.0 (2, 0, 0) versions ← [1.2.3, 1.10.0, 1.2.10, 2.0.0]
102versions→ [1.2.3, 1.10.0, 1.2.10, 2.0.0] = [103 Version("1.2.3"),104 Version("1.10.0"),105 Version("1.2.10"),106 Version("2.0.0")107]108109print(f"Versions: {versions[1.2.3, 1.10.0, 1.2.10, 2.0.0]}")110print(f"Sorted: {sorted(versions[1.2.3, 1.10.0, 1.2.10, 2.0.0])}")outputVersions: [1.2.3, 1.10.0, 1.2.10, 2.0.0]def __lt__(self, other):
pass 1 of 696def __lt__(self1.10.0, other1.2.3):97 return self.parts(1, 10, 0) < other.parts(1, 2, 3)All 6 passes — pass 1 is the card above pass selfotherself.partsother.parts1 1.10.0 1.2.3 (1, 10, 0) (1, 2, 3) 2 1.2.10 1.10.0 (1, 2, 10) (1, 10, 0) 3 1.2.10 1.10.0 (1, 2, 10) (1, 10, 0) 4 1.2.10 1.2.3 (1, 2, 10) (1, 2, 3) 5 2.0.0 1.2.10 (2, 0, 0) (1, 2, 10) 6 2.0.0 1.10.0 (2, 0, 0) (1, 10, 0) print(f"Sorted: {sorted(versions)}")
109print(f"Versions: {versions}")110print(f"Sorted: {sorted(versions[1.2.3, 1.10.0, 1.2.10, 2.0.0])}")111112# Money class113print("\nMoney class:")114115@total_ordering116class Money:117 def __init__(self, amount, currency='USD'):118 self.amount = amount119 self.currency = currency120 121 def __eq__(self, other):122 if self.currency != other.currency:123 raise ValueError("Cannot compare different currencies")124 return self.amount == other.amount125 126 def __lt__(self, other):127 if self.currency != other.currency:128 raise ValueError("Cannot compare different currencies")129 return self.amount < other.amount130 131 def __repr__(self):132 return f"${self.amount:.2f} {self.currency}"133134prices = [135 Money(19.99),136 Money(5.99),137 Money(12.50),138 Money(25.00)139]outputSorted: [1.2.3, 1.2.10, 1.10.0, 2.0.0] Money class:self.amount ← 19.99, self.currency ← USD
pass 1 of 4116class Money:117 def __init__(self(empty), amount19.99, currencyUSD='USD'):118 self.amount→ 19.99 = amount19.99119 self.currency→ USD = currencyUSDAll 4 passes — pass 1 is the card above pass amountself.amountself.currency1 19.99 19.99 USD 2 5.99 5.99 USD 3 12.5 12.5 USD 4 25.0 25.0 USD prices ← [$19.99 USD, $5.99 USD, $12.50 USD, $25.00 USD]
134prices→ [$19.99 USD, $5.99 USD, $12.50 USD, $25.00 USD] = [135 Money(19.99),136 Money(5.99),137 Money(12.50),138 Money(25.00)139]140141print(f"Prices: {prices[$19.99 USD, $5.99 USD, $12.50 USD, $25.00 USD]}")142print(f"Cheapest: {min(prices[$19.99 USD, $5.99 USD, $12.50 USD, $25.00 USD])}")143print(f"Most expensive: {max(prices)}")outputPrices: [$19.99 USD, $5.99 USD, $12.50 USD, $25.00 USD]def __lt__(self, other):
pass 1 of 6126def __lt__(self$5.99 USD, other$19.99 USD):127 if self.currency != other.currency:128 raise ValueError("Cannot compare different currencies")129 return self.amount5.99 < other.amount19.99All 6 passes — pass 1 is the card above pass selfotherself.amountother.amount1 $5.99 USD $19.99 USD 5.99 19.99 2 $12.50 USD $5.99 USD 12.5 5.99 3 $25.00 USD $5.99 USD 25.0 5.99 4 $5.99 USD $19.99 USD 5.99 19.99 5 $12.50 USD $19.99 USD 12.5 19.99 6 $25.00 USD $19.99 USD 25.0 19.99 print(f"Cheapest: {min(prices)}")
141print(f"Prices: {prices}")142print(f"Cheapest: {min(prices[$19.99 USD, $5.99 USD, $12.50 USD, $25.00 USD])}")143print(f"Most expensive: {max(prices[$19.99 USD, $5.99 USD, $12.50 USD, $25.00 USD])}")outputCheapest: $5.99 USDdef __eq__(self, other):
121def __eq__(self$25.00 USD, other$19.99 USD):122 if self.currency != other.currency:123 raise ValueError("Cannot compare different currencies")124 return self.amount25.0 == other.amount19.99print(f"Most expensive: {max(prices)}")
142print(f"Cheapest: {min(prices)}")143print(f"Most expensive: {max(prices[$19.99 USD, $5.99 USD, $12.50 USD, $25.00 USD])}")144145# Date class146print("\nDate class:")147148@total_ordering149class SimpleDate:150 def __init__(self, year, month, day):151 self.year = year152 self.month = month153 self.day = day154 155 def __eq__(self, other):156 return (self.year, self.month, self.day) == \157 (other.year, other.month, other.day)158 159 def __lt__(self, other):160 return (self.year, self.month, self.day) < \161 (other.year, other.month, other.day)162 163 def __repr__(self):164 return f"{self.year}-{self.month:02d}-{self.day:02d}"165166dates = [167 SimpleDate(2024, 5, 15),168 SimpleDate(2023, 12, 1),169 SimpleDate(2024, 1, 10),170 SimpleDate(2024, 5, 1)171]outputMost expensive: $25.00 USD Date class:self.year ← 2024, self.month ← 5, self.day ← 15
pass 1 of 4149class SimpleDate:150 def __init__(self(empty), year2024, month5, day15):151 self.year→ 2024 = year2024152 self.month→ 5 = month5153 self.day→ 15 = day15All 4 passes — pass 1 is the card above pass yearmonthdayself.yearself.monthself.day1 2024 5 15 2024 5 15 2 2023 12 1 2023 12 1 3 2024 1 10 2024 1 10 4 2024 5 1 2024 5 1 dates ← [2024-05-15, 2023-12-01, 2024-01-10, 2024-05-01]
166dates→ [2024-05-15, 2023-12-01, 2024-01-10, 2024-05-01] = [167 SimpleDate(2024, 5, 15),168 SimpleDate(2023, 12, 1),169 SimpleDate(2024, 1, 10),170 SimpleDate(2024, 5, 1)171]172173print(f"Dates: {dates[2024-05-15, 2023-12-01, 2024-01-10, 2024-05-01]}")174print(f"Sorted: {sorted(dates[2024-05-15, 2023-12-01, 2024-01-10, 2024-05-01])}")outputDates: [2024-05-15, 2023-12-01, 2024-01-10, 2024-05-01]def __lt__(self, other):
pass 1 of 6159def __lt__(self2023-12-01, other2024-05-15):160 return (self.year2023, self.month12, self.day1) < \161 (other.year2024, other.month5, other.day15)All 6 passes — pass 1 is the card above pass selfotherself.yearself.monthself.dayother.yearother.monthother.day1 2023-12-01 2024-05-15 2023 12 1 2024 5 15 2 2024-01-10 2023-12-01 2024 1 10 2023 12 1 3 2024-01-10 2024-05-15 2024 1 10 2024 5 15 4 2024-01-10 2023-12-01 2024 1 10 2023 12 1 5 2024-05-01 2024-01-10 2024 5 1 2024 1 10 6 2024-05-01 2024-05-15 2024 5 1 2024 5 15 print(f"Sorted: {sorted(dates)}")
173print(f"Dates: {dates}")174print(f"Sorted: {sorted(dates[2024-05-15, 2023-12-01, 2024-01-10, 2024-05-01])}")175176# Range checking177print("\nRange checking:")178179@total_ordering180class Score:181 def __init__(self, value):182 self.value = value183 184 def __eq__(self, other):185 return self.value == other.value186 187 def __lt__(self, other):188 return self.value < other.value189 190 def __repr__(self):191 return f"Score({self.value})"192193score = Score(75)194min_score = Score(60)outputSorted: [2023-12-01, 2024-01-10, 2024-05-01, 2024-05-15] Range checking:self.value ← 75
pass 1 of 3180class Score:181 def __init__(self(empty), value75):182 self.value→ 75 = value75All 3 passes — pass 1 is the card above pass valueself.value1 75 75 2 60 60 3 100 100 score ← Score(75)
193score→ Score(75) = Score(75)194min_score = Score(60)195max_score = Score(100)min_score ← Score(60)
193score = Score(75)194min_score→ Score(60) = Score(60)195max_score = Score(100)max_score ← Score(100)
194min_score = Score(60)195max_score→ Score(100) = Score(100)196197print(f"Score: {scoreScore(75)}")198print(f"In range [60, 100]? {min_scoreScore(60) <= scoreScore(75) <= max_scoreScore(100)}")outputScore: Score(75)def __lt__(self, other):
pass 1 of 2187def __lt__(selfScore(60), otherScore(75)):188 return self.value60 < other.value75def __lt__(self, other):
pass 2 of 2187def __lt__(selfScore(75), otherScore(100)):188 return self.value75 < other.value100PRIORITIES ← (empty)
197print(f"Score: {score}")198print(f"In range [60, 100]? {min_scoreScore(60) <= scoreScore(75) <= max_scoreScore(100)}")199200# Priority201print("\nPriority:")202203@total_ordering204class Task:205 PRIORITIES→ (empty) = {'low': 3, 'medium': 2, 'high': 1}206 207 def __init__(self, name, priority):208 self.name = name209 self.priority = priority210 211 def __eq__(self, other):212 return self.PRIORITIES[self.priority] == \213 self.PRIORITIES[other.priority]214 215 def __lt__(self, other):216 return self.PRIORITIES[self.priority] < \217 self.PRIORITIES[other.priority]218 219 def __repr__(self):220 return f"Task('{self.name}', '{self.priority}')"221222tasks = [223 Task("Write docs", "low"),224 Task("Fix bug", "high"),225 Task("Review code", "medium"),226 Task("Deploy", "high")227]outputIn range [60, 100]? True Priority:self.name ← Write docs, self.priority ← low
pass 1 of 4207def __init__(self(empty), nameWrite docs, prioritylow):208 self.name→ Write docs = nameWrite docs209 self.priority→ low = prioritylowAll 4 passes — pass 1 is the card above pass namepriorityself.nameself.priority1 Write docs low Write docs low 2 Fix bug high Fix bug high 3 Review code medium Review code medium 4 Deploy high Deploy high tasks ← [Task('Write docs', 'low'), Task('Fix bug', 'high'), Task('Review code', 'medium'), Task('Deploy', 'high')]
222tasks→ [Task('Write docs', 'low'), Task('Fix bug', 'high'), Task('Review code', 'medium'), Task('Deploy', 'high')] = [223 Task("Write docs", "low"),224 Task("Fix bug", "high"),225 Task("Review code", "medium"),226 Task("Deploy", "high")227]228229print("Tasks:")230for t in tasks:outputTasks:for t in tasks:
pass 1 of 4229print("Tasks:")230for tTask('Write docs', 'low') in tasks[Task('Write docs', 'low'), Task('Fix bug', 'high'), Task('Review code', 'medium'), Task('Deploy', 'high')]:231 print(f" {tTask('Write docs', 'low')}")output Task('Write docs', 'low')All 4 passes — pass 1 is the card above pass t1 Task('Write docs', 'low') 2 Task('Fix bug', 'high') 3 Task('Review code', 'medium') 4 Task('Deploy', 'high') print(" Sorted by priority:")
233print("\nSorted by priority:")234for t in sorted(tasks):output Sorted by priority:def __lt__(self, other):
pass 1 of 6215def __lt__(selfTask('Fix bug', 'high'), otherTask('Write docs', 'low')):216 return self.PRIORITIES[self.priority]1 < \217 self.PRIORITIES[other.priority]3All 6 passes — pass 1 is the card above pass selfotherself.PRIORITIES[self.priority]self.PRIORITIES[other.priority]1 Task('Fix bug', 'high') Task('Write docs', 'low') 1 3 2 Task('Review code', 'medium') Task('Fix bug', 'high') 2 1 3 Task('Review code', 'medium') Task('Write docs', 'low') 2 3 4 Task('Review code', 'medium') Task('Fix bug', 'high') 2 1 5 Task('Deploy', 'high') Task('Review code', 'medium') 1 2 6 Task('Deploy', 'high') Task('Fix bug', 'high') 1 1 for t in sorted(tasks):
pass 1 of 4233print("\nSorted by priority:")234for tTask('Fix bug', 'high') in sorted(tasks[Task('Write docs', 'low'), Task('Fix bug', 'high'), Task('Review code', 'medium'), Task('Deploy', 'high')]):235 print(f" {tTask('Fix bug', 'high')}")output Task('Fix bug', 'high')All 4 passes — pass 1 is the card above pass t1 Task('Fix bug', 'high') 2 Task('Deploy', 'high') 3 Task('Review code', 'medium') 4 Task('Write docs', 'low')
Exercise: practical.py
Implement a cached recursive function and create partial functions for common operations