日期:2020年2月28日
作者:Commas
注释:学习就是为了忘记,接上一章《Python3之闭包浅谈》,现在讲一下Python装饰器;
如果您想了解更多有关Python的知识,那么请点《我的Python浅谈系列目录》
一、装饰器前言
装饰器(Decorator)
是一个装饰函数的函数,本质就是一个函数,用来在不修改
被装饰函数的源代码与调用方式的前提下,对被装饰函数进行功能扩展
的函数。掌握装饰器前需要学习以下4点知识:
- 函数的本质就是一个指向函数本体的内存地址,执行函数的方法为
函数名()
; - 闭包(closure)知识;
- 开放封闭原则(OCP,Open Closed Principle):对扩展是开放的,而对修改是封闭的;
- 函数的元组参数(*args)与字典参数(**kwargs)
二、装饰器初识
首先我们有一个func函数,如下:
def func():
time.sleep(1)
print("执行了func()函数")
如果我们需要测试函数的执行时间,我们是否可以简单粗暴的在函数内部加个时间计算的代码,如下:
import time
def func():
# 标记开始执行时间
start_time = time.time()
# 函数原逻辑代码
time.sleep(1)
print("执行了func()函数")
# 标记结束执行时间
end_time = time.time()
# 计算函数执行时间,并打印
delta_time = end_time - start_time
print("{}的执行时间:{}".format(f, delta_time))
一分钟不到,搞定测试函数执行时间,但是却怎么看着怎么别扭,函数内部增加了很多计算时间代码,有种掩盖原逻辑的赶脚,一点都不优雅;倘若有一百个函数需要测试执行时间,那就工作量可想而知,于是我们想办法,有没有不改变原函数源代码与调用方式,但是又可以计算出原函数,我们先写一个计算执行时间的函数,如下:
def calculate_time(f):
"""装饰器函数"""
def wrapper():
start_time = time.time()
f()
end_time = time.time()
delta_time = end_time - start_time
print("{}的执行时间:{}".format(f, delta_time))
# 将传入额函数地址返回到外部,即不调用则不执行
return wrapper
def func():
"""需要被装饰的函数,测试此函数的执行时间"""
time.sleep(1)
print("执行了func()函数")
# (1)调用装饰器函数
# func 是一个标识符,此时func被覆盖为calculate_time()中的wrapper
print("【原来的func()函数】函数名:{},地址:{}".format(func.__name__, func))
func = calculate_time(func)
print("【现在的func()函数】函数名:{},地址:{}".format(func.__name__, func))
# (2)执行func()函数
# calculate_time()中的wrapper()函数,同时会执行原来的func()
print("---准备调用func()---")
func()
# =======控制台输出结果=======
【原来的func()函数】函数名:func,地址:<function func at 0x000002C3E38A98C8>
【现在的func()函数】函数名:wrapper,地址:<function calculate_time.<locals>.wrapper at 0x000002C3E38A9950>
---准备调用func()---
执行了func()函数
<function func at 0x000002C3E38A98C8>的执行时间:1.0002367496490479
# =======控制台输出结果=======
虽然最后func()函数发生改变,但是并未改变原函数源代码,而且调用方式也未改变,就相当于给原func()函数扩展了一个计算执行时间的功能,新func() = 原func() + 计算执行时间的功能
,这也是聪明的前辈们总结出来——最原始的Python装饰器,后面随着Python的发展,有了一个调用装饰器的语法糖,语法如下:
@装饰器名称
def func_name():
"""被装饰函数"""
pass
于是,上述代码等价于:
import time
def calculate_time(f):
"""装饰器函数"""
def wrapper():
start_time = time.time()
f()
end_time = time.time()
delta_time = end_time - start_time
print("{}的执行时间:{}".format(f, delta_time))
# 将传入额函数地址返回到外部,即不调用则不执行
return wrapper
@calculate_time
def func():
"""需要被装饰的函数,测试此函数的执行时间"""
time.sleep(1)
print("执行了func()函数")
func()
版权声明:本文为博主原创文章,如需转载,请给出:
原文链接:https://blog.csdn.net/qq_35844043/article/details/104457037