推薦:[http://www.wklken.me/posts/2013/08/18/python-extra-functools.html]
由于經(jīng)常在tensorflow的代碼中看到functools這個(gè)函數(shù)埃疫,有不太明白就寫了這個(gè)博文。
*************************************************傳說(shuō)中的分割線*********************************************
functools的常見(jiàn)函數(shù):其中最常見(jiàn)的自然是functools.partial
- functools.partial
- functool.update_wrapper
- functool.wraps
- functools.reduce
- functools.cmp_to_key
- functools.total_ordering
functools.partial
functools.partial的作用和tensorflow的slim很像榄檬,主要作用就是簡(jiǎn)化函數(shù)诞仓,更少更靈活的函數(shù)參數(shù)調(diào)用涮雷。
functools.partial可以讓我們通過(guò)包裝的方法,減少你的函數(shù)參數(shù)僻族。
源代碼:
#args/keywords 調(diào)用partial時(shí)參數(shù)
def partial(func, *args, **keywords):
def newfunc(*fargs, **fkeywords):
newkeywords = keywords.copy()
newkeywords.update(fkeywords)
return func(*(args + fargs), **newkeywords) #合并婚惫,調(diào)用原始函數(shù),此時(shí)用了partial的參數(shù)
newfunc.func = func
newfunc.args = args
newfunc.keywords = keywords
return newfunc
partial將你傳入的參數(shù)保存氨鹏,如果你需要使用的時(shí)候則添加進(jìn)入欧募。
示例:
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)
#<class 'functools.partial'>
可以看出返回的其實(shí)是一個(gè)partial類型的變量压状,實(shí)際相當(dāng)于在partial中保存了需要調(diào)用的函數(shù)以及參數(shù)仆抵,在需要調(diào)用的時(shí)候?qū)㈩A(yù)先設(shè)置的參數(shù)傳入?yún)?shù)列表。
functool.update_wrapper
默認(rèn)partial對(duì)象沒(méi)有name和doc, 這種情況下种冬,對(duì)于裝飾器函數(shù)非常難以debug.使用update_wrapper(),從原始對(duì)象拷貝或加入現(xiàn)有partial對(duì)象
它可以把被封裝函數(shù)的name镣丑、module、doc和 dict都復(fù)制到封裝函數(shù)去(模塊級(jí)別常量WRAPPER_ASSIGNMENTS, WRAPPER_UPDATES)
說(shuō)白了就是沒(méi)有加@functools.wraps的函數(shù)娱两,裝飾器@返回的是函數(shù)名是原本的但是其函數(shù)簽名等內(nèi)部參數(shù)說(shuō)明卻是裝飾原函數(shù)的那個(gè)函數(shù)的莺匠。
使用了@functools.wraps的函數(shù),它能夠幫助你在裝飾器@保存被裝飾的函數(shù)的函數(shù)內(nèi)部簽名等信息十兢。
#!/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__)
# hello2()
print(hello2.__name__)
print(hello2.__doc__)
#call_it
#wrap func: call_it
#hello2
#test hello
functool.wraps
實(shí)驗(yàn)發(fā)現(xiàn)其實(shí)這個(gè)是對(duì)于update_wrapper的再次簡(jiǎn)化趣竣,與之前的函數(shù)有區(qū)別的地方在于:
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
相當(dāng)于@functools.wraps(func)這句話代替了update_wrapper(call_it, func),其他的輸出結(jié)果相同旱物。