5-8日读书笔记

7.1 7.1 7.1 装饰器基础知识

装饰器是可调用的对象,其参数是另一个函数(被装饰的函数)。装饰器可能会处理被装饰的函数,然后把它返回,或者将其替换成另一个函数或者可调用对象。

示例如下:

>>> @hello
... def target():
...     print('running man')
... 

>>> 
>>> def target():
...     print('running man')
... 
>>> target = hello(target)

上面两种写法的最终结果一致:上述两个代码片段执行完毕后得到的target不一定是原来那个target函数,而是hello(target)返回的函数。

装饰器通常会把函数替换成另一个函数

>>> def deco(func):
...     def inner():
...             print('running man')
...     return inner
... 
>>> @deco
... def target():
...     print('running woman')
... 
>>> target()
running man
>>> target
<function deco.<locals>.inner at 0x10f6fcc80>

deco返回的是inner函数对象,那么当使用deco装饰target的时候,实际上就会运行inner函数,审查该对象时,也能发现target现在实际上是inner的引用。

语法糖(Syntactic sugar),也译为糖衣语法,是由英国计算机科学家彼得·蘭丁发明的一个术语,指计算机语言中添加的某种语法,这种语法对语言的功能没有影响,但是更方便程序员使用。 语法糖让程序更加简洁,有更高的可读性。

装饰器其实只是语法糖,它可以像常规的可调用对象那样调用,其参数是另一个函数。

python何时执行装饰器

装饰器的一个关键特性就是,它们在被装饰的函数定义之后回立刻运行。

>>> registry = []
>>> def register(func):
...     print('running register(%s)' % func)
...     registry.append(func)
...     return func
... 
>>> @register
... def test1():
...     print('running test1')
... 
running register(<function test1 at 0x10f6fcbf8>)
>>> 
>>> @register
... def test2():
...     print('running test2')
... 
running register(<function test2 at 0x10f6fcd08>)
>>> def main():
...     print('running main')
...     print('registry ->', registry)
...     test1()
...     test2()
... 
>>> if __name__ == '__main__':
...     main()
... 
running main
registry -> [<function test1 at 0x10f6fcbf8>, <function test2 at 0x10f6fcd08>]
running test1
running test2

函数装饰器在导入模块时立即执行,而被装饰的函数只在明确调用时运行。

装饰器函数与被装饰的函数在同一个模块中定义。实际情况是,装饰器通常是在一个模块中被定义,然后应用在其他的模块中的函数上。
register装饰器返回的函数与通过参数传入的相同。

很多Python Web框架使用这样的装饰器把函数添加到某种中央注册处,例如把url模式映射到生成HTTP响应的函数上的注册处。

多数的装饰器会修改被装饰的函数。通常,他们会定义一个内部函数,然后将其返回,替换被装饰的函数。使用内部函数的代码几乎都要靠闭包才能正确运作。
那么,想要了解闭包,先要理解变量作用域。

变量作用域规则

>>> def f1(a):
...     print(a)
...     print(b)
... 
>>> f1(3)
3
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in f1
NameError: name 'b' is not defined
>>> b = 6
>>> f1(3)
3
6

上面是一个很简单的例子。第一次调用f1时,并没有定义变量b,因此出现报错。

>>> b = 6
>>> def f2(a):
...     print(a)
...     print(b)
...     b = 8
... 
>>> f2(2)
2
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in f2
UnboundLocalError: local variable 'b' referenced before assignment

在看这个例子,虽然全局中对变量b赋值了,但还是报错了。
原因是Python在编译函数体时,它判断出b是局部变量。因为在函数体中给他赋值了。生成的字节码证实了这种判断,Python会尝试从本地环境中获取b。

如果在函数中赋值时想让解释器把b当成全局的变量,要用global声明:

>>> b = 6
>>> def f2(a):
...     global b
...     print(a)
...     print(b)
...     b = 8
... 
>>> f2(2)
2
6
>>> b
8
>>> f2(2)
2
8

这样就不会出现报错了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值