python 挂钩函数

挂钩函数在 sort 中的使用1

根据挂钩函数的返回值进行排序

names = ['Socrates', 'Archimedes', 'Plato', 'Aristotle']
names.sort(key=lambda x: len(x))
print(names)

输出

['Plato', 'Socrates', 'Aristotle', 'Archimedes']

挂钩函数在 defaultdict 中的使用2

字典 current 没有 increments 中的键时候,打印日志信息

from collections import defaultdict

current = {'green': 12, 'blue': 3}
increments = [
    ('read', 5),
    ('blue', 17),
    ('orange', 9),
]

def log_missing():
    print('key  added')
    return 0

result = defaultdict(log_missing, current)
print('before: ', dict(result))
for key,  amount in increments:
    result[key] += amount
print('after: ', dict(result))

输出

before:  {'green': 12, 'blue': 3}
key  added
key  added
after:  {'green': 12, 'blue': 20, 'read': 5, 'orange': 9}

利用闭包特性,统计添加的键个数
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

print(increment_with_report(current, increments))

输出

(defaultdict(<function increment_with_report.<locals>.missing at 0x000001EDBCB64670>, {'green': 12, 'blue': 20, 'read': 5, 'orange': 9}), 2)

缺点:把带状态的闭包函数用作挂钩有一个缺点,就是读起来比无状态的函数难懂一些。


优化1,使用类来保存
class CountMissing:
    def __init__(self):
        self.added = 0

    def missing(self):
        self.added += 1
        return 0


counter = CountMissing()
result = defaultdict(counter.missing, current)
for key, amount in increments:
    result[key] += amount

print(counter.added)

输出

2

缺点:使用辅助类来改写带状态的闭包,相对要清晰一些,但是不易理解CountMissing 对象需要由谁来构建? missing 方法由谁来调用?该类是否需要添加新的公共方法? 这些都需要看过 defaultdict 的用法后才能明白。


优化2,利用类的 call 方法

感觉还是难以理解

class CountMissing:
    def __init__(self):
        self.added = 0

    def __call__(self, *args, **kwargs):
        self.added += 1
        return 0


counter = CountMissing()
result = defaultdict(counter, current)
for key, amount in increments:
    result[key] += amount

print(counter.added)

输出

2

__call__ 方法表明 CountMissing 的类实例也会像函数那样,在合适的时候充当某个 API 使用。于是,刚读到这段代码的人就可以从这个方法开始,来理解 CountMissing 类的主要功能。 __call__ 方法强烈暗示了该类的用途,它告诉我们,这个类的功能相当于一个带状态的闭包。

上一篇:defaultdict用法


下一篇:collections 使用教程