python之functools
一、functools——高级函数和可调函数的操作
除了我们经常使用的map和filter方法以外,此包还定义了一些额外的functools
二、常见的函数
1、cmp_to_key(func):将之前python2的sorted排序指定的cmp转换为现在python3支持的key
2、@functools.lru_cache(maxsize = 128,typed = False)
装饰器可以装饰函数,可以缓存函数的结果保存相应的调用。可以减少频繁调用相同的函数使用相同参数的I/O消耗
因为使用dict来缓存数据,位置参数和关键字参数都都必须可哈希
如果maxsize设置为None,就会禁用LRU,cache就会无限增长。当maxsize设置为2的次方,LRU特性表现最好
typed 是否检查数据类型是否相同。
为了评估缓存的效率,调整maxsize参数,这个函数被cache_info函数包裹,会返回一个命名元祖,显示:hits(命中)、misses(未命中)、maxsize和currsize(当前大小)。在多线程环境下,hits和misses只是近似值
装饰器同样提供了cache_clear()用来清除和使cache失效
原来的函数可以通过__wrapped__属性访问。在自省、传递缓存或以另外一种cache来包裹函数。
LRU工作起来最好,当最近的调用一般预测这接下来要调用的(新闻服务器最流行的文章每天都会改变)。cache的大小限制缓存大小,保证长时间运行的进行比如web服务器不会无限增长。
实例:web静态页面
@lru_cache(maxsize=32) def get_pep(num): 'Retrieve text of a Python Enhancement Proposal' resource = 'http://www.python.org/dev/peps/pep-%04d/' % num try: with urllib.request.urlopen(resource) as s: return s.read() except urllib.error.HTTPError: return 'Not Found' >>> for n in 8, 290, 308, 320, 8, 218, 320, 279, 289, 320, 9991: ... pep = get_pep(n) ... print(n, len(pep)) >>> get_pep.cache_info() CacheInfo(hits=3, misses=8, maxsize=32, currsize=8)
实例:高效计算斐波那契数列:
@lru_cache(maxsize=None) def fib(n): if n < 2: return n return fib(n-1) + fib(n-2) >>> [fib(n) for n in range(16)] [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610] >>> fib.cache_info() CacheInfo(hits=28, misses=16, maxsize=None, currsize=16)
3、@functools.total_ordering一个类只要定义一个或多个对比排序方法,类装饰器自动补充剩余的,简化了需要书写所有的对比函数
只要实现_
_lt__()
, __le__()
, __gt__()
, or __ge__()中的一个。而且,类必须提供__eq__方法。
例如:
@total_ordering class Student: def _is_valid_operand(self, other): return (hasattr(other, "lastname") and hasattr(other, "firstname")) def __eq__(self, other): if not self._is_valid_operand(other): return NotImplemented return ((self.lastname.lower(), self.firstname.lower()) == (other.lastname.lower(), other.firstname.lower())) def __lt__(self, other): if not self._is_valid_operand(other): return NotImplemented return ((self.lastname.lower(), self.firstname.lower()) < (other.lastname.lower(), other.firstname.lower()))
注意:尽管装饰器是创建有序类型更加便捷,但是会消耗慢执行的消耗和更加复杂的栈跟踪对于衍生的对比方法。所以实现6个对比方法而不是提供两个使用装饰器,效率更高。意味着大家不要用哈!
4、functools.partial(func,*args,**keywords)偏函数
偏函数主要用于 某些函数 的参数是固定的,我们重新生成一个新的函数,执行偏函数,就不用再提供固定的参数,偏函数会生成一个新的函数
>>> from functools import partial >>> basetwo = partial(int, base=2) >>> basetwo.__doc__ = 'Convert base 2 string to an int.' >>> basetwo('10010') 18
5、functools.partialmethod(func,*args,**keywords)
返回一个新的偏函数的描述符,虽然看起来和partial很像,但是仅仅用于函数定义,而不是直接调用
6、functools.reduce(function, iterable[, initializer])
逐渐调用sequence的元素作为函数的两个参数,将其变为一个单值。例如:reduce(lambda x,y: x+y, [1, 2, 3, 4, 5])
calculates ((((1+2)+3)+4)+5)
7、@functools.singledispatch(default)
8、functools.
update_wrapper
(wrapper, wrapped, assigned=WRAPPER_ASSIGNMENTS, updated=WRAPPER_UPDATES)
9、@
functools.
wraps
(wrapped, assigned=WRAPPER_ASSIGNMENTS, updated=WRAPPER_UPDATES)