LoginSignup
3
1

More than 5 years have passed since last update.

EP 23 Accept Functions for Simple Interfaces Instead of Classes

Last updated at Posted at 2016-04-08
  • 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.
1. class with __call__
2. class
3. 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

3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1