装饰器与闭包的学习
装饰器
初识装饰器
装饰器(decorator)实际上是一个函数,用来改变其他函数的功能,如果我们有一个函数,功能为打印一句话
本文的代码格式炸了,我也很无力,明明是对的
1 | def f1(): |
现在我们需要改变打印的内容,但是不能修改此函数中的打印语句,那么我们可以添加一个函数,修改f1这个引用指向的对象为新的函数
1 | def decorator(func): |
运行f1,得到的结果如下
1 | f1() |
可以看到,我们成功地改变了原函数的打印语句,上面的decorator函数即为python中的装饰器,我们可以使用语法糖@将上面的python代码简化
1 |
|
Python何时执行装饰器
装饰器在模块导入时即执行,而不是显示调用被装饰的函数时才执行,下面我们来看一个例子
1 | registry = [] |
如果上面的py文件当做脚本运行,那么可以得到结果:
1 | running register(<function f1 at 0x100f962a8>) |
如果是当做模块导入,那么结果为:
1 | running register(<function f1 at 0x100f962a8>) |
这也证实了装饰器在模块导入时运行
装饰器的功能
从上面的例子可以看到,我们可以将工程中的register函数定义为装饰器,其他功能函数在使用之前必须要经过装饰器注册后才能使用,在需要临时取消某些函数功能时,只需要去掉语法糖”@”即可,功能强大且非常灵活、
1 | registry = [] |
在上面的例子中,f1和f2两个功能函数启用,f3被禁用,manager函数实现对所有启用的函数进行操作。
Python变量的作用域
python变量遵循”LEGB”原则,L(local),E(enclosing),G(global),B(built-in),即解释器在寻找变量时,会现在函数内部(local)里寻找,如果找不到,去外层函数(enclosing)中寻找,最后去全局变量(global)和内建(built-in)中寻找,下面看一个例子
1 | b = 1 |
显然,最终的输出结果为
1 | 2 |
这是因为解释器把b当做了全局变量打印,现在我们稍作修改
1 | b = 1 |
现在的输出结果为
1 | 2 |
现在的变量b是局部(local)变量,解释器优先在local里寻找,而不是global,我们再加修改
1 | b = 1 |
输出结果为
1 | 3 |
这是因为此时的b在编译阶段被确认为局部变量,但是我们未经赋值就进行使用,所以会报错!