functools模塊用于高級函數(shù):作用于或返回其他函數(shù)的函數(shù)赏胚,一般來說,任何可調(diào)用對象都可以作為這個模塊的用途來處理羔巢。
1檩小、lru_cache
@functools.lru_cache(maxsize=128, typed=False)
使用functools模塊的lur_cache裝飾器,可以緩存最多 maxsize 個此函數(shù)的調(diào)用結果杜耙,從而提高程序執(zhí)行的效率搜骡,特別適合于耗時的函數(shù)。參數(shù)maxsize為最多緩存的次數(shù)佑女,如果為None记靡,則無限制,設置為2n時团驱,性能最佳摸吠;如果 typed=True(注意,在 functools32 中沒有此參數(shù))嚎花,則不同參數(shù)類型的調(diào)用將分別緩存寸痢,例如 f(3) 和 f(3.0)。
被 lru_cache 裝飾的函數(shù)會有 cache_clear 和 cache_info 兩個方法紊选,分別用于清除緩存和查看緩存信息啼止。
from functools import lru_cache
@lru_cache(maxsize=32)
def fib(n):
print('calling the fib function....')
if n < 2:
return n
return fib(n-1) + fib(n-2)
if __name__ == '__main__':
print(list([fib(n) for n in range(16)]))
[print(func) for func in dir(fib) if not func.startswith('_')]
print(fib.cache_info())
print('------------')
print([fib(n) for n in range(16)])
運行結果:
如果把第二次調(diào)用的參數(shù)改為大于16的數(shù),注意看結果
可以看出兵罢,在已經(jīng)緩存的數(shù)據(jù)中献烦,不會進行重復調(diào)用函數(shù),但是卖词,未被緩存的數(shù)據(jù)將再次調(diào)用函數(shù)仿荆。
2、partial
functools.partial(func, *args, **keywords)
大致如下:
def partial(func, *args, **keywords):
def newfunc(*fargs, **fkeywords):
newkeywords = keywords.copy()
newkeywords.update(fkeywords)
return func(*(args + fargs), **newkeywords)
newfunc.func = func
newfunc.args = args
newfunc.keywords = keywords
return newfunc
可以看出函數(shù)partial的返回值是一個partial類坏平,該類有三個只讀屬性
partial.func:可調(diào)用的對象或函數(shù)
partial.args:最左邊的位置參數(shù)將被預先提交給partial對象調(diào)用所提供的位置參數(shù)
partial.keywords:當調(diào)用partial對象時拢操,將提供關鍵字參數(shù).
3.reduce
functools.reduce(function, iterable[, initializer])
大致如下:
def reduce(function, iterable, initializer=None):
it = iter(iterable)
if initializer is None:
value = next(it)
else:
value = initializer
for element in it:
value = function(value, element)
return value
4.update_wrapper
functools.update_wrapper(wrapper, wrapped, assigned=WRAPPER_ASSIGNMENTS, updated=WRAPPER_UPDATES)
找不到很好的解釋該函數(shù)的材料,于是舶替,看了一下源碼:
WRAPPER_ASSIGNMENTS = ('__module__', '__name__', '__doc__')
WRAPPER_UPDATES = ('__dict__',)
def update_wrapper(wrapper,
wrapped,
assigned = WRAPPER_ASSIGNMENTS,
updated = WRAPPER_UPDATES):
"""Update a wrapper function to look like the wrapped function
wrapper is the function to be updated
wrapped is the original function
assigned is a tuple naming the attributes assigned directly
from the wrapped function to the wrapper function (defaults to
functools.WRAPPER_ASSIGNMENTS)
updated is a tuple naming the attributes of the wrapper that
are updated with the corresponding attribute from the wrapped
function (defaults to functools.WRAPPER_UPDATES)
"""
for attr in assigned:
setattr(wrapper, attr, getattr(wrapped, attr))
for attr in updated:
getattr(wrapper, attr).update(getattr(wrapped, attr, {}))
# Return the wrapper so this can be used as a decorator via partial()
return wrapper
5.wraps
@functools.wraps(wrapped, assigned=WRAPPER_ASSIGNMENTS, updated=WRAPPER_UPDATES)
是不是覺得這坨跟update_wrapper很像令境,是的,他其實調(diào)用了update_wrapper,像下面:
def wraps(wrapped,
assigned = WRAPPER_ASSIGNMENTS,
updated = WRAPPER_UPDATES):
"""Decorator factory to apply update_wrapper() to a wrapper function
Returns a decorator that invokes update_wrapper() with the decorated
function as the wrapper argument and the arguments to wraps() as the
remaining arguments. Default arguments are as for update_wrapper().
This is a convenience function to simplify applying partial() to
update_wrapper().
"""
return partial(update_wrapper, wrapped=wrapped,
assigned=assigned, updated=updated)
怎么樣顾瞪,使用partial固定住三個關鍵字參數(shù)以后,開始使用update_wrapper函數(shù)調(diào)用舔庶,只需傳入wrapper參數(shù)即可。具體例子說明會更清晰:
from functools import update_wrapper,wraps
def my_decorator1(f):
def wrapper(*args, **kwds):
print('Calling decorated function')
return f(*args, **kwds)
return update_wrapper(wrapper=wrapper ,wrapped=f)
def my_decorator2(f):
@wraps(f)
def wrapper(*args, **kwds):
print('Calling decorated function')
return f(*args, **kwds)
return wrapper
@my_decorator1
def example():
"""Docstring"""
print('Called example function')
if __name__ == '__main__':
# process result:
# Calling decorated function
# Called example function
example()
# add wraps decorator reuslt is :example Docstring __main__
# print example.__name__, example.__doc__, example.__module__
# not add wraps decorator reuslt is :wrapper None __main__
print('example_name: %s, example_doc: %s, example_module: %s '%(example.__name__, example.__doc__, example.__module__))
上面的例子中陈醒,wraps裝飾器的參數(shù)是my_decorator2裝飾器的參數(shù)惕橙,本例中也是example函數(shù),在wraps調(diào)用partial函數(shù)時钉跷,wrapped參數(shù)值就賦值為example函數(shù)弥鹦。我們知道wraps函數(shù)的返會結果是可調(diào)用partial對象,該對象的func屬性時update_wrapper.所以my_decorator2的功能實際上和my_decorator1功能是相同的。