挂钩函数在 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__
方法强烈暗示了该类的用途,它告诉我们,这个类的功能相当于一个带状态的闭包。