Python装饰器深入全面理解(2)

如果你在别处见过Python装饰器的使用,你可能会疑惑,我们实现的func装饰器跟你见过的装饰器不都一样,因为在实际应用中,装饰器大多是与“@”符号结合起来使用。其实“@”符号所实现的功能就是 do_something = func(do_something)这行代码的功能。来,我们尝试一下使用“@”:

def func(f): def inner_func(): print('{}函数开始运行……'.format(f.__name__)) f() print('{}函数结束运行……'.format(f.__name__)) return inner_func @func def do_something(): print('正在完成功能') if __name__ == '__main__': do_something()

输出结果:

do_something函数开始运行……

正在完成功能

do_something函数结束运行……

之前我们知道,func函数就是一个装饰器,所以使用“@”符号时,我们只需要在被装饰的函数前面加上“@func”就表示该函数被func装饰器装饰,在需要处直接调用do_something函数即可。

2.2 为什么要用装饰器

在上面代码中,我们写了一个装饰器func,在这个装饰器中,使用装饰器的好处就已经初见端倪了。

(1)可以在不对被装饰函数做任何修改的前提下,给被装饰函数附加上一些功能。使用@func对do_something函数进行装饰时,我们没有对do_something函数的代码做什么的改变,但是被装饰后的do_something函数却多了开始运行和结束运行的功能。

(2)不改变被装饰函数的调用方式。在被装饰前,我们通过do_something()调用这个函数,被装饰后,还是通过do_something()调用这个函数。

(3)代码更加精简。在上面代码中,我们只是用@func装饰了do_something一个函数,但是如果有多个函数需要添加开始运行和结束运行的提示功能,如果不用装饰器,那么就需要对每一个函数进行修改,则工作量和需要修改的代码量……用了装饰器之后,只需要在需要添加这一功能的函数前面添加@func就可以了。

一言以盖之,装饰器可以在不改变原函数调用方式和代码情况下,为函数添加一些功能,使代码更加精简。

我们在写一个装饰器来加深一下理解。相比大家都写过代码来统计一个函数的运行时间的功能,我们使用装饰器来实现一下这个功能:

import time def timmer(f): def inner_func(): start_time = time.time() f() end_time = time.time() print('{}函数运行消耗时间为:{}'.format(f.__name__, end_time-start_time)) return inner_func @timmer def do_something(): print('do_something函数运行……') time.sleep(1) if __name__ == '__main__': do_something()

输出结果:

do_something函数运行……

do_something函数运行消耗时间为:1.000662088394165

在上面例子中,我们首先定义了一个计时装饰器timmer,当需要统计某个函数运行时间时,只需要在函数定义时,在前面添加一行写上@timmer即可,例如上面对do_something函数运行时间进行统计,对do_something原来要实现什么功能就继续实现这一功能,原来代码该怎样还怎样,该怎么调用还怎么调用。所以说,使用装饰器可以在不改变原函数代码和调用方式的情况下附加上其他功能。

如果你阅读到了这里,我想你对装饰器已经有了初步的理解。接下来,我们继续聊一聊更加复杂的装饰器。

3 深入理解装饰器 3.1 被装饰的函数带返回值

我们上面写的两个装饰器所装饰的do_something函数是没有返回值的,但大多数函数可都是有返回值的。针对有返回值的函数,装饰器该怎么写呢?

def func(f): def inner_func(): print('{}函数开始运行……'.format(f.__name__)) ret = f() print('{}函数结束运行……'.format(f.__name__)) return ret # 这里返回值 return inner_func @func def do_something(): print('正在完成功能') return '我是返回值' if __name__ == '__main__': ret = do_something() print(ret)

输出结果:

do_something函数开始运行……

正在完成功能

do_something函数结束运行……

我是返回值

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/b06b6a34177ef29eb92256fd117164fe.html