ITPub博客

首页 > 应用开发 > > python装饰器:函数装饰器的表现方式

python装饰器:函数装饰器的表现方式

作者:nt1979 时间:2019-10-12 10:36:25 0 删除 编辑

谁可以作为装饰器(可以将谁编写成装饰器):

函数

方法

实现了__call__的可调用类

装饰器可以去装饰谁(谁可以被装饰):

函数

方法

类

基础:函数装饰器的表现方式

假如你已经定义了一个函数funcA(),在准备定义函数funcB()的时候,如果写成下面的格式:

1 @funcA

2 def funcB():...

表示用函数funcA()装饰函数funcB()。当然,也可以认为是funcA包装函数funcB。它等价于:

1 def funcB():...

2

3 funcB = funcA(funcB)

也就是说,将函数funcB作为函数funcA的参数,funcA会重新返回另一个可调用的对象(比如函数)并赋值给funcB。

所以,funcA要想作为函数装饰器,需要接收函数作为参数,并且返回另一个可调用对象(如函数)。例如:

1 def funcA(F):

2 ...

3 ...

4 return Callable

注意,函数装饰器返回的可调用对象并不一定是原始的函数F,可以是任意其它可调用对象,比如另一个函数。但最终,这个返回的可调用对象都会被赋值给被装饰的函数变量(上例中的funcB)。

函数可以同时被多个装饰器装饰,后面的装饰器以前面的装饰器处理结果为基础进行处理:

1 @decorator1

2 @decorator2

3 def func():...

4

5 # 等价于

6 func = decorator1(decorator2(func))

当调用被装饰后的funcB时,将自动将funcB进行装饰,并调用装饰后的对象。所以,下面是等价的调用方式:

1 funcB() # 调用装饰后的funcB

2 funcA(funcB)()

了解完函数装饰器的表现后,大概也能猜到了,装饰器函数可以用来扩展、增强另外一个函数。实际上,内置函数中staticmethod()、classmethod()和property()都是装饰器函数,可以用来装饰其它函数。

两个简单的例子

例如,函数f()返回一些字符串,现在要将它的返回结果转换为大写字母。可以定义一个函数装饰器来增强函数f()。

1 def toupper(func):

2 def wrapper(*args, **kwargs):

3 result = func(*args, **kwargs)

4 return result.upper()

5 return wrapper

6 @toupper

7 def f(x: str): # 等价于f = toupper(f)

8 return x

9 res = f("abcd")

10 print(res)

上面toupper()装饰f()后,调用f("abcd")的时候,等价于执行toupper(f)("abcd"),参数"abcd"传递给装饰器中的wrapper()中的*args,在wrapper中又执行了f("abcd"),使得原本属于f()的整个过程都完整了,最后返回result.upper(),这部分是对函数f()的扩展部分。

注意,上面的封装函数wrapper()中使用了*args **kwargs,是为了确保任意参数的函数都能正确执行下去。

再比如要计算一个函数autodown()的执行时长,可以额外定义一个函数装饰器timecount()。

执行结果:

1 autodown 0.004986763000488281

2 autodown 0.05684685707092285

3 autodown 0.5336081981658936

上面wrapper()中的return是多余的,是因为这里装饰的autodown()函数自身没有返回值。但却不应该省略这个return,因为timecount()可以去装饰其它可能有返回值的函数。

觉得文章还不错的话不妨收藏起来慢慢看,有任何建议或看法欢迎大家在评论区分享讨论!

来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/4822/viewspace-3167132/ ,如需转载,请注明出处,否则将追究法律责任。

下一篇: 数据库锁机制
请登录后发表评论 登录
全部评论

注册时间:2019-08-05

  • 博文量
    318
  • 访问量
    17306