Python函数装饰器高级用法 (2)

示例:

import functools from clockdeco import clock @functools.lru_cache() @clock def fibonacci(n): if n < 2: return n return fibonacci(n-2) + fibonacci(n-1) if __name__=='__main__': print(fibonacci(6))

优化了递归算法,执行时间会减半。

注意,lru_cache可以使用两个可选的参数来配置,它的签名如下:

functools.lru_cache(maxsize=128, typed=False)

maxsize:最大存储数量,缓存满了以后,旧的结果会被扔掉。

typed:如果设为True,那么会把不同参数类型得到的结果分开保存,即把通常认为相等的浮点数和整型参数(如1和1.0)区分开。

functools.singledispatch

Python3.4的新增语法,可以用来优化函数中的大量if/elif/elif。使用@singledispatch装饰的普通函数会变成泛函数:根据第一个参数的类型,以不同方式执行相同操作的一组函数。所以它叫做single dispatch,单分派。

根据多个参数进行分派,就是多分派了。

示例,生成HTML,显示不同类型的Python对象:

import html def htmlize(obj): content = html.escape(repr(obj)) return '<pre>{}</pre>'.format(content)

因为Python不支持重载方法或函数,所以就不能使用不同的签名定义htmlize的变体,只能把htmlize变成一个分派函数,使用if/elif/elif,调用专门的函数,比如htmlize_str、htmlize_int等。时间一长htmlize会变得很大,跟各个专门函数之间的耦合也很紧密,不便于模块扩展。

@singledispatch经过深思熟虑后加入到了标准库,来解决这类问题:

from functools import singledispatch from collections import abc import numbers import html @singledispatch def htmlize(obj): # 基函数 这里不用写if/elif/elif来分派了 content = html.escape(repr(obj)) return '<pre>{}</pre>'.format(content) @htmlize.register(str) def _(text): # 专门函数 content = html.escape(text).replace('\n', '<br>\n') return '<p>{0}</p>'.format(content) @htmlize.register(numbers.Integral) def _(n): # 专门函数 return '<pre>{0} (0x{0:x})</pre>'.format(n) @htmlize.register(tuple) @htmlize.register(abc.MutableSequence) def _(seq): # 专门函数 inner = '</li>\n<li>'.join(htmlize(item) for item in seq) return '<ul>\n<li>' + inner + '</li>\n</ul>'

@singledispatch装饰了基函数。专门函数使用@<<base_function>>.register(<<type>>)装饰,它的名字不重要,命名为_,简单明了。

这样编写代码后,Python会根据第一个参数的类型,调用相应的专门函数。

小结

本文首先介绍了典型的函数装饰器:把被装饰的函数换成新函数,二者接受相同的参数,而且返回被装饰的函数本该返回的值,同时还会做些额外操作。接着介绍了装饰器的两个高级用法:叠放装饰器和参数化装饰器,它们都会增加函数的嵌套层级。最后介绍了3个标准库中的装饰器:保留原有函数属性的functools.wraps、缓存耗时的函数结果的functools.lru_cache和优化if/elif/elif代码的functools.singledispatch。

参考资料:

《流畅的Python》

https://github.com/fluentpython/example-code/tree/master/07-closure-deco

https://blog.csdn.net/liuzonghao88/article/details/103586634

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zzxygs.html