python基础(functools)

推荐:[http://www.wklken.me/posts/2013/08/18/python-extra-functools.html]
由于经常在tensorflow的代码中看到functools这个函数,有不太明白就写了这个博文。
*************************************************传说中的分割线*********************************************
functools的常见函数:其中最常见的自然是functools.partial

  • functools.partial
  • functool.update_wrapper
  • functool.wraps
  • functools.reduce
  • functools.cmp_to_key
  • functools.total_ordering
functools.partial functools.partial的作用和tensorflow的slim很像,主要作用就是简化函数,更少更灵活的函数参数调用。
functools.partial可以让我们通过包装的方法,减少你的函数参数。
源代码:
#args/keywords 调用partial时参数 def partial(func, *args, **keywords): def newfunc(*fargs, **fkeywords): newkeywords = keywords.copy() newkeywords.update(fkeywords) return func(*(args + fargs), **newkeywords) #合并,调用原始函数,此时用了partial的参数 newfunc.func = func newfunc.args = args newfunc.keywords = keywords return newfunc

【python基础(functools)】partial将你传入的参数保存,如果你需要使用的时候则添加进入。
示例:
def add(a, b): return a + b print add(4, 2) plus3 = partial(add, 4) plus5 = partial(add, 5) print plus3(2) print plus3(7) print plus5(10) # 6 # 6 # 11 # 15 type(plus3) #

可以看出返回的其实是一个partial类型的变量,实际相当于在partial中保存了需要调用的函数以及参数,在需要调用的时候将预先设置的参数传入参数列表。
functool.update_wrapper 默认partial对象没有name和doc, 这种情况下,对于装饰器函数非常难以debug.使用update_wrapper(),从原始对象拷贝或加入现有partial对象
它可以把被封装函数的name、module、doc和 dict都复制到封装函数去(模块级别常量WRAPPER_ASSIGNMENTS, WRAPPER_UPDATES)
说白了就是没有加@functools.wraps的函数,装饰器@返回的是函数名是原本的但是其函数签名等内部参数说明却是装饰原函数的那个函数的。
使用了@functools.wraps的函数,它能够帮助你在装饰器@保存被装饰的函数的函数内部签名等信息。
#!/usr/bin/env python # encoding: utf-8def 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__) # hello2() print(hello2.__name__) print(hello2.__doc__) #call_it #wrap func: call_it #hello2 #test hello

functool.wraps 实验发现其实这个是对于update_wrapper的再次简化,与之前的函数有区别的地方在于:
def wrap2(func): @functools.wraps(func) def call_it(*args, **kwargs): """wrap func: call_it2""" print('before call') return func(*args, **kwargs) return call_it

相当于@functools.wraps(func)这句话代替了update_wrapper(call_it, func),其他的输出结果相同。

    推荐阅读