- Instead of defining and instantiating classes, functions are often all you need for simple interfaces between components in Python.
- References to functions and methods in Python are first class, meaning they can be used in expressions like any other type.
- The
__call__
special method enables instances of a class to be called like plain Python functions. - When you need a function to maintain state, consider defining a class that provides the
__call__
method instead of defining a stateful closure.
Effective Python
Statefull expression should use class with __call__
.
Prieference for stateful expression.
- class with
__call__
- class
- statefull closure
from collections import defaultdict
current = dict(green=12, blue=3)
increments = [
('red', 5),
('blue', 17),
('orange', 9)
]
# Utilize `__call__` is simple and the best way
# We just call the instance of the class
class BetterCoutMissing:
def __init__(self):
self.added = 0
def __call__(self):
self.added += 1
return 0
counter = BetterCoutMissing()
result = defaultdict(counter, current)
for key, amount in increments:
result[key] += amount
assert counter.added == 2
# class is better way to hold state
# But it is unclear how to instantiate and to call missing
class CountMissing:
def __init__(self):
self.added = 0
def missing(self):
self.added += 1
return 0
counter = CountMissing()
result = defaultdict(count.missing, current)
for key, amount in increments:
result[key] += amount
assert counter.added == 2
# Verbse, hard to read
# It is good to use closure to encapcell state, though.
def increment_with_report(current, increments):
added_count = 0
def missing():
nonlocal added_count
added_count += 1
return 0
result = defaultdict(missing, current)
for key, amount in increments:
result[key] += amount
return result, added_count
result, count = increment_with_report(current, increments)
assert count == 2