《Fluent Python》学习笔记 chpter7函数装饰器
来源:互联网 发布:网络平面设计课程 编辑:程序博客网 时间:2024/05/16 12:16
《Fluent Python》学习笔记系列7
装饰器的基础知识
装饰器是可调用的对象,其参数是另一个函数(被装饰的函数)。 装饰器可能会处理被装饰的函数,然后把它返回,或者将其替换成另一个函数或可调用对象。从语法上来讲,函数装饰器就是其后边函数运行时的声明。
在定义函数或方法的def
语句之前的一行,以@
开头,后边跟着是元函数。
如,有名为decorate的装饰器:
class C: @decorate def target():
这个语法就等同于:
target = decorate(target)
也就是把函数传递给装饰器,然后再赋值给最初的变量名。
class C: def target(): ... target = decorate(target)
装饰器执行
装饰器的一个关键特性是,它们在被装饰的函数定义之后立即运行。
registry = []def register(func): print('running register(%s)' % func) registry.append(func) return func @register def f1(): print('running f1()')@registerdef f2(): print('running f2()')def f3(): print('running f3()')def main(): print('running main()') print('registry ->', registry) f1() f2() f3()if __name__=='__main__': main()
执行结果:
running register(<function f1 at 0x000001BC7DF210D0>)running register(<function f2 at 0x000001BC7DF21158>)running main()registry -> [<function f1 at 0x000001BC7DF210D0>, <function f2 at 0x000001BC7DF21158>]running f1()running f2()running f3()
可以看出,在主程序main
执行之前,register
已经执行了两次。调用register
时,传入的参数是被装饰的函数,如f1
和 f2
。 所以函数装饰器在导入模块的时候就已经执行了,而被装饰的函数只在明确调用时运行。这也是导入时与运行时 之间的区别。
在真实代码中,装饰器的用法为:
- 装饰器通常在一个模块中定义,然后应用到其他模块中的函数上。
- 大多数装饰器会在内部定义一个函数,然后将其返回。
变量作用域规则
>>> b = 6>>> def f2(a):... print(a)... print(b)... b = 9...>>> f2(3)3Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 3, in f2UnboundLocalError: local variable 'b' referenced before assignment>>>
注:因为在Python 编译函数的定义体时,它判断 b 是局部变量,因为在函数中给它赋值。生成的字节码证实了这种判断,Python 会尝试从本地环境获取 b 。后面调用 f2(3) 时,f2 的定义体会获取并打印局部变量 a 的值,但是尝试获取局部变量 b 的值时,发现 b 没有绑定值。
这不是缺陷,而是设计选择:Python 不要求声明变量,但是假定在函数定义体中赋值的变量是局部变量。
如果在函数中赋值时想让解释器把 b 当成全局变量,要使用 global 声明:
>>> b = 6>>> def f3(a):... global b... print(a)... print(b)... b = 9...>>> f3(3)36>>> b9>>> f3(3)39
闭包
闭包指延伸了作用域的函数,其中包含函数定义体中引用、但是不在定义体中定义的非全局变量。函数是不是匿名的没有关系,关键是它能访问定义体之外定义的非全局变量。
实现方法有多种。
首先,可以使用类来实现:
class Averager(): def __init__(self): self.series = [] def __call__(self, new_value): self.series.append(new_value) total = sum(self.series) return total/len(self.series)
Averager
的实例是可调用对象:
>>> avg = Averager()>>> avg(10)10.0>>> avg(11)10.5>>> avg(12)11.0
来可以使用函数实现:
def make_averager(): series = [] def averager(new_value): series.append(new_value) total = sum(series) return total/len(series)return averager
调用 make_averager 时,返回一个 averager 函数对象。每次调用 averager 时,它会把参数添加到系列值中,然后计算当前平均值。
series 是 make_averager 函数的局部变量,因为那个函数的定义体中初始化了series : series = [] 。可是,调用 avg(10) 时, make_averager 函数已经返回了,而它的本地作用域也一去不复返了。在 averager 函数中, series 是自由变量(free variable)。这是一个技术术语,指未在本地作用域中绑定的变量。
nonlocal 声明
nonlocal与global相似,但是它只是作用于嵌套作用域,而且只是作用在函数里面
Python 3 引入了 nonlocal 声明。它的作用是把变量标记为自由变量,即使在函数中为变量赋予新值了,也会变成自由变量。
def make_averager(): count = 0 total = 0 def averager(new_value): nonlocal count, total count += 1 total += new_value return total / count return averager
程序中,count,total在函数averager内声明为nonlocal,赋值会修改最近的嵌套函数的本地作用域中的名称。
全局声明将会将变量映射至整个模块。当嵌套函数存在时,嵌套函数中的变量 也许仅仅是引用,但是需要
nonlocal
声明才可可以修改。
- 《Fluent Python》学习笔记 chpter7函数装饰器
- python 学习笔记---匿名函数 装饰器 偏函数
- python学习笔记,返回函数,匿名函数,装饰器
- 《Fluent Python》学习笔记chapter 8
- python 函数装饰器学习
- 【Python学习笔记】函数式编程:装饰器
- python学习笔记 匿名函数和装饰器
- Python装饰器学习笔记
- Python学习笔记:装饰器
- python装饰器学习笔记
- Python学习笔记--装饰器
- Python装饰器学习笔记
- Python学习笔记-装饰器
- Python 装饰器 学习笔记
- "Python"学习笔记----装饰器
- 【Python学习笔记】装饰器
- python学习笔记-装饰器
- python装饰器学习笔记
- JavaScript之XML
- 目录监控
- C++空间复杂度计算方法
- msxml3.dll 错误 '80072efd' ---asp 网站报错
- contos7安装vsftp部署FTP服务器
- 《Fluent Python》学习笔记 chpter7函数装饰器
- 遇到Kotlin使用中的问题,及解决办法
- 解决Maven打war包同一个jar有不同的日期版本号的问题
- 二维数组专题讲义
- 欢迎使用CSDN-markdown编辑器
- qt开发环境
- js设计模式与开发实践2
- ORA-01652:unable to extend temp segment by 128 in tablespace TEMPTS1
- 深入理解JAVA虚拟机读书笔记----调优案例分析与实战