functools 模块中有三个主要的函数 partial(), update_wrapper() 和 wraps()。
1、partial(func[,args][, *keywords])
functools.partial 通过包装手法,允许我们 "重新定义" 函数签名。用一些默认参数包装一个可调用对象,返回结果是可调用对象,并且可以像原始对象一样对待冻结部分函数位置函数或关键字参数,简化函数,更少更灵活的函数参数调用。
from functools import partial
int2 = partial(int, base=2)
print int2('11') # 3
print int2('101') # 5
当函数的参数个数太多,需要简化时,使用functools.partial
可以创建一个新的函数,这个新函数可以固定住原函数的部分参数,从而在调用时更简单。
2、functool.update_wrapper
默认partial对象没有__name__和__doc__, 这种情况下,对于装饰器函数非常难以debug.使用update_wrapper(),从原始对象拷贝或加入现有partial对象。它可以把被封装函数的__name__、module、__doc__和 __dict__都复制到封装函数去(模块级别常量WRAPPER_ASSIGNMENTS, WRAPPER_UPDATES)。
这个函数主要用在装饰器函数中,装饰器返回函数反射得到的是包装函数的函数定义而不是原始函数定义
>>> functools.WRAPPER_ASSIGNMENTS
('__module__', '__name__', '__doc__')
>>> functools.WRAPPER_UPDATES
('__dict__',)
#!/usr/bin/env python # encoding: utf-8 def wrap(func): def call_it(*args, **kwargs): """wrap func: call_it""" print 'before call' return func(*args, **kwargs) return call_it @wrap def hello(): """say hello""" print 'hello world' from functools import update_wrapper def wrap2(func): def call_it(*args, **kwargs): """wrap func: call_it2""" print 'before call' return func(*args, **kwargs) return update_wrapper(call_it, func) @wrap2 def hello2(): """test hello""" print 'hello world2' if __name__ == '__main__': hello() print hello.__name__ print hello.__doc__ print hello2() print hello2.__name__ print hello2.__doc__
结果: before call hello world call_it wrap func: call_it before call hello world2 hello2 test hello
3、functool.wraps
调用函数装饰器partial(update_wrapper, wrapped=wrapped, assigned=assigned, updated=updated)的简写。
from functools import wraps
def wrap3(func):
@wraps(func)
def call_it(*args, **kwargs):
"""wrap func: call_it2"""
print 'before call'
return func(*args, **kwargs)
return call_it
@wrap3
def hello3():
"""test hello 3"""
print 'hello world3'
结果:
before call
hello world3
hello3
test hello 3
详见:http://www.wklken.me/posts/2013/08/18/python-extra-functools.html