python functools 用法总结
1, functools.cmp_to_key(key)
Python3的sorted函数可以给定一个key函数,如下
sorted(data, key=key_func)
其中key_func将一个元素转换成可用来比较的值,被称为key functions.
与之相对的是comparison functions,接受两个输入,返回比较的结果。如:
comp_func(x, y) # will return the result of comparison between x and y.
functools.cmp_to_key就是将comparision functions包装一下,使其能够传入需要key functions的地方,比如sorted函数。
2, @functools.lru_cache(maxsize=128, typed=False)
lru_cache是一个decorator,能够给function缓存能力。
maxsize设定了缓存的大小,根据官方文档,最好是2的次幂。取None则无上限。
typed如果设为True,则同值不同类型的argument会被分开存储。如3和3.0
为了方便评估缓存的效果,被decorated的函数被加装上一个cache_info函数。可以返回:hits, misses, maxsize and currsize
此外还有加装cache_clear函数,用于清理缓存。
Lru_cache适合的情况,在当未来的调用很大机会是最近的调用。这样可以避免重复的计算或IO。
不要用在有side effect的函数上,不要用在需要返回distinct object的函数上,也不要用在time或random这样的impure function。
加在算斐波那契数量的递归函数上,真是挺巧的。
3, @functools.total_ordering
这是一个class decorator.
一共有六种比较运算符<, >, <=, >=, ==, !=。当一个类想要重载这些运算符,需要实现 lt(), gt(), le(), ge(), eq(),
functools.total_ordering的功能就是当重载比较运算符时,可以只实现其中一两种,其他的会自动生成。
根据官文,有两点注意:1是必须要有__eq__,2是这种方法生产的重载可能会稍慢。如果这里出现效率问题,最好还是自己全部实现。
4,functools.partial(func, *args, **keywords)
输入一个函数及其部分参数,返回一个新的函数。
新的函数的功能可以解释为旧的函数+部分fixed参数。
5, functools.partialmethod(func, *args, **keywords)
和4差不多,只不过用在类的method上。
会自动加self。
6,functools.reduce(function, iterable[, initializer])
即map reduce里的reduce操作。
7,@functools.singledispatch
用于方便的编写一个能够处理不同类型输入参数的函数。
好用,但是用法描述起来略复杂。
以官方例子来描述:
#首先定义函数
from functools import singledispatch
@singledispatch
def fun(arg, verbose=False):
if verbose:
print("Let me just say,", end=" ")
print(arg)
#然后注册不同类型的处理函数
@fun.register
def _(arg: int, verbose=False):
if verbose:
print("Strength in numbers, eh?", end=" ")
print(arg)
@fun.register
def _(arg: list, verbose=False):
if verbose:
print("Enumerate this:")
for i, elem in enumerate(arg):
print(i, elem)
这样函数就会根据不同的输入参数类型调用不同的处理流程了。
8, functools.update_wrapper(wrapper, wrapped, assigned=WRAPPER_ASSIGNMENTS, updated=WRAPPER_UPDATES)
将wrapped函数的元数据(module, name, qualname, annotations and doc)复制给wrapper函数。
用于在定义一个decorator的时候,返回的wrapper函数并不具有元数据,需要用此方式添加。
9,@functools.wraps(wrapped, assigned=WRAPPER_ASSIGNMENTS, updated=WRAPPER_UPDATES)
即8的decorator版本。调用起来方便很多。
例:
from functools import wraps
def my_decorator(f):
@wraps(f)
def wrapper(*args, **kwds):
print('Calling decorated function')
return f(*args, **kwds)
return wrapper