python function at 0x00000_Python 中的函数装饰器和闭包

本文是《流畅的Python》第7章的学习笔记。

函数装饰器可以被用于增强方法的某些行为,如果想自己实现装饰器,则必须了解闭包的概念。

装饰器的基本概念

装饰器是一个可调用对象,它的参数是另一个函数,称为被装饰函数。装饰器可以修改这个函数再将其返回,也可以将其替换为另一个函数或者可调用对象。

例如:有个名为 decorate 的装饰器:@decorate

def target():

print('running target()')

上述代码的写法和以下写法的效果是一样的:def target():

print('running target()')

target = decorate(target)

但是,它们返回的 target 不一定是原来的那个 target 函数,例如下面这个例子:>>> def deco(func):

...     def inner():

...         print('running inner()')

...     return inner

...

>>> @deco

... def target():

...     print('running target()')

...

>>> target()

running inner()

>>> target

.inner at 0x0000013D88563040>

可以看到,调用 target 函数执行的是 inner 函数,这里的 target 实际上是 inner 的引用。

何时执行装饰器

装饰器的另一个关键特性是,它们在被装饰函数定义时立即执行,这通常是发生在导入模块的时候。

例如下面的这个模块:registration.py# 存储被装饰器 @register 装饰的函数

registry = []

# 装饰器

def register(func):

print(f"注册函数 -> {func}")

# 记录被装饰的函数

registry.append(func)

return func

@register

def f1():

print("执行 f1()")

@register

def f2():

print("执行 f2()")

def f3():

print("执行 f3()")

if __name__ == "__main__":

print("执行主函数")

print("registry -> ", registry)

f1()

f2()

f3()

现在我们在命令行执行这个脚本:$ python registration.py

注册函数 -> 

注册函数 -> 

执行主函数

registry ->  [, ]

执行 f1()

执行 f2()

执行 f3()

这里我们可以看到,在主函数执行之前,register  已经执行了两次。加载模块后,registry 中已经有两个被装饰函数的引用:f1 和 f2。不过这两个函数以及 f3  都是在脚本中明确调用后才开始执行的。

如果只是单纯的导入 registration.py 模块而不运行:>>> import registration

注册函数 -> 

注册函数 -> 

查看 registry 中的值:>>> registration.registry

[, ]

这个例子主要说明:装饰器在导入模块时立即执行,而被装饰的函数只有在明确调用时才运行。这也突出了 Python 中导入时和运行时这个两个概念的区别。

在装饰器的实际使用中,有两点和示例是不同的:示例中装饰器和被装饰函数在同一个模块中。实际使用中,装饰器通常在一个单独的模块中定义,然后再应用到其它模块的函数上。

示例中 register  装饰器返回的函数和传入的参数相同。实际使用中,装饰器会在内部定义一个新函数,然后将其返回。

装饰器内部定义并返回新函数的做法需要靠闭包才能正常运作。为了理解闭包,则必须先了解 Python 中的变量作用域。

变量作用域的规则

我们来看下面这个例子,一个函数读取一个局部变量 a,一个全局变量 b。>>> def f1(a):

...     print(a)

...     print(b)

...

>>> f1(3)

3

Traceback (most recent call last):

File "", line 1, in 

File "", line 3, in f1

NameError: name 'b' is not defined

出现错误并不奇怪。如果我们先给 b 赋值,再调用  f1,那就不会出错了:>>> b = 1

>>> f1(3)

3

1

现在,我们来看一个不寻常的例子:>>> b &

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值