4.把函数当作对象
4.1闭包
#计算移动平均值
def make_averager():
count = 0
total = 0
def averager(new_value):
nonlocal count, total
count += 1
total += new_value
return total / count
return averager
#test
ave = make_averager()
ave(10)
ave(20)
4.2装饰器
#一个简单的装饰器,支持处理关键字参数
import time
DEFAULT_FMT = '[{elasped:0.8f}s] {name} {name}({args}) -> {result}'
def clock(fmt=DEFAULT_FMT):
def decorate(func):
def clocked(*_args):
t0 = time.time()
_result = func(*_args)
elasped = time.time() - t0
name = func.__name__
args = ', '.join(repr(arg) for arg in _args)
result = repr(_result)
print(fmt.format(**locals()))
return _result
return clocked
return decorate
@clock()
def snooze(seconds):
time.sleep(seconds)
for i in range(3):
snooze(.123)
4.3单分派泛函数
#functools.singledspatch装饰器可以把整体方案拆分为多个模块,使用@singledspatch装饰的普通函数会变为泛函数:根据第一个参数的类型,以不同的方式执行相同的操作的一组函数
from functools import singledspatch
from collections import abc
from numbers
from html
@singledspatch
def htmlize(obj):
content = html.escape(repr(obj))
return '<pre>{}</pre>'.format(content)
@htmlize.register(str)
def _(text):
content = html.escape(text).replace('\n', '<br>\n')
return '<p>{0}</p>'.format(content)
@htmlize.register(numbers.Integral)
def _(n):
return '<pre>{0} (0x{0:x})</pre>'.format(n)
@htmlize.register(tuple)
@htmlize.register(abc.MutableSequence)
def _(seq):
inner = '</li>\n<li>'.join(htmlize(item) for item in seq)
return '<ul>\n<li>' + inner + '</li>\n</ul>
4.4参数化装饰器
#为了便于启用或禁用register执行的函数注册功能,我们为它提供了一个可选的active参数,设为False时,不注册被装饰的函数
registry = set()
def register(active=False):
def decorator(func):
print('running register(active=%s) -> decorator(%s)'
% (active,func))
if active:
registry.add(func)
else:
registry.discard(func)
return func
return decorator
@register(active=False)
def f1():
print('running f1')
@register(active=True)
def f2(active=True):
print('running f2')
def f3():
print('runing f3')
#test
registry
#为了接受新参数,新的register装饰器必须作为函数调用
register(active=True)(f3)
registry
register(active=False)(f2)
registry