Python 装饰器(decorator)

发布时间:18-05-0912:46

Python装饰器是一个很有用的功能,在很多场合都有使用,决定花点时间好好研究,现归纳总结如下:

先看看一些实例, 然后再来分析下原理 假设我们有如下的基本函数

defdo_something():

for i in range(1000000):

pass

print ("play game")

do_something()

结果如下:

play game

需求: 统计函数的执行时间

1. 不是装饰器的装饰器

这种实现看上去还可以,但是每次调用的是decorator,还要把函数作为一个参数传入,使用起来就不方便了。

2. 最简单的装饰器

装饰器是在函数定义时前面加@,然后跟装饰器的实现函数。可以看出,现在只要直接调用do_something就可以了。调用的地方不要作任何修改。

3. 目标函数带固定参数的装饰器

实现很简单, 就是给wrapper函数参加相同的参数

4. 目标函数带不固定参数的装饰器

需求2: 目标函数每次调用重复执行指定的次数

5. 让装饰器带参数

6. 原理

看了这么多实例, 装饰器的基本类型也基本上都有了。是不是清楚了呢? 如果还是不清楚,那就继续看下面的内容。

6.1 不带参数的装饰器

@a_decorator

deff(...):

...

#经过a_decorator后, 函数f就相当于以f为参数调用a_decorator返回结果。

f = a_decorator(f)

来分析这个式子, 可以看出至少要满足以下几个条件 1. 装饰器函数运行在函数定义的时候 2. 装饰器需要返回一个可执行的对象 3. 装饰器返回的可执行对象要兼容函数f的参数

6.2 验证分析

6.2.1 装饰器运行时间

可以看出, 这里的do_something并没有调用, 但是却打印了decorator, 可wrapper没有打印出来。也就是说decorator是在do_something调用的时候执行的。

6.2.2 返回可执行的对象

6.2.3 兼容函数f的

6.2.3 兼容函数f的参数

看到这里, 至少对不带参数的装饰器应该全弄清楚了, 也就是说能到看山还是山了。

6.3 带参数的装饰器

这里就给一个式子, 剩下的问题可以自己去想

@decomaker(argA, argB, ...)

deffunc(arg1, arg2, ...):

pass

#这个式子相当于

func = decomaker(argA, argB, ...)(func)

6.4 被装饰过的函数的函数名

可以看出, do_something的函数名变成了wrapper,这不是我们想要的。原因估计各位也都清楚了。那要怎么去解决呢?

但是这个看起来是不是很不专业, python的functools.wraps提供了解决方法

到此为止, 你是不是觉得已经完全明白了呢? 但事实是, 这其实还不够

7. 装饰器类

需求3: 让函数只能运行指定的次数.

前面我们讲的都是函数式的装饰器, 那么类能不能成为装饰器呢?

结果如下:

play game

play game 1

play game

play game 1

play game

play game 1

play game

play game 1

play game

play game 1

play game

play game 1

play game

play game 1

play game

play game 1

play game

play game 1

do_something run more than 10 times

play game 1

play game 1

play game 1

play game 1

play game 1

do_something1 run more than 15 times

是不是感觉有点怪, 但它确实是可行的。 在Python中, 其实函数也是对象。 反过来, 对象其实也可以像函数一样调用, 只要在类的方法中实现__call__方法。回想一下创建对象的过程

这其实和函数调用没

带参数的装饰器 fun = A.__init__(args)(fun) 不带参数的装饰器 fun = A.__init__(fun)()

现在装饰器的内容基本差不多了。 还有一些问题, 可以自己去尝试研究。

返回顶部