写在前面:Fluent Python 系列是学习《Fluent Python》的笔记 ~
函数装饰器这是一本适合Python进阶的书,不仅有一些高级语法,作者对部分底层实现也有讲解,以便于我们理解Python的设计,比如为什么普通字典是无序的呢?
- 1 变量作用域
- 2 闭包
- 3 装饰器
- 3.1 基本概念和写法
- 3.2 装饰器何时执行
- 3.3 标准库中常用的两个装饰器函数
- 3.4 参数化装饰器
- 4 小结
注意函数体内赋值的局部变量与函数体外同名全局变量
2 闭包
3 装饰器 3.1 基本概念和写法
import time
from clockedeco import clock
from functools import lru_cache
@clock
def snooze(seconds):
time.sleep(seconds)
#@clock
#def factorial(n):
# return 1 if n < 2 else factorial(n-1)
def factorial(n):
return 1 if n < 2 else factorial(n-1)
factorial = clock(factorial)
@lru_cache()
@clock
def fibonacci(n):
if n < 2 :
return n
else:
return fibonacci(n-2) + fibonacci(n-1)
if __name__ == '__main__':
# print('*' * 40, 'Calling snooze(.123)')
# snooze(.123) # 此时调用的已经是被装饰过的函数
# print('*' * 40, 'Calling factorial(6)')
# print('6!=', factorial(6))
print(fibonacci(6))
3.2 装饰器何时执行
registry = []
# 定义装饰器
def register(func):
print('running register(%s)' % func)
registry.append(func)
return func
# 定义被装饰的函数
@register
def f1():
print('running f1()')
def f3():
print('runing f3()')
def main():
print('running main()')
print('registry->', registry)
f1() # 调用被装饰的函数
f3()
if __name__ == '__main__':
main()
3.3 标准库中常用的两个装饰器函数
from functools import singledispatch
from collections import abc
import numbers
import html
@singledispatch
def htmlize(obj):
"""处理Object类型的基函数"""
content = html.escape(repr(obj))
return '{}'.format(content)
# 以下各个专门函数使用@《base_function》.register()装饰
@htmlize.register(str)
def _(text): # 专门函数的名称无关紧要
content = html.escape(text).replace('n', '
n')
return '{0}
'.format(content)
@htmlize.register(numbers.Integral)
def _(n):
return '{0} (0x{0:x})'.format(n)
@htmlize.register(tuple)
@htmlize.register(abc.MutableSequence)
def _(seq):
inner = 'n- n
- ' + inner + ' n
3.4 参数化装饰器
我所用到的函数装饰器的场景:
-
优化递归函数:跟书中介绍的例子相同,斐波那契数列有一种解法便称之为“备忘录”,就是将已经计算出的结果保存在数组中,eg:保存f(1), f(2),这样在计算f(3)=f(1)+f(2)的时候就不需要再重复计算f(1)和f(2),只需要在数组中查找即可。Python内嵌的装饰器实现了备忘录的功能,不需要手动再设置数组保存结果,直接使用@lru_cache装饰器即可。
https://leetcode-cn.com/problems/fibonacci-number/
2.使用Python实现类似C++/Java 函数重载的功能
Python确实没有函数重载,遇到针对不同情况调用不同函数的时候,最简单的方法就是使用if-elif-else分别调用专门的函数,这种做法的扩展性确实不好。



