Python装饰器理解和固定格式
闭包
闭包函数,可以简单一句话概括,即内层函数引用外层函数的变量,并且进行调用执行,即该内层函数就是是一个闭包函数。
举例子:
def outside():
a = "哈哈!"
def inside(): # 当前inside函数即为一个闭包函数
print(a)
return inside
装饰器
装饰器,简单理解就是程序代码在运行中,在函数前面动态增加的功能方式。
举例子:
假设当前我们计算1-1000万相加。
def test_sum():
sum_result = 0
for i in range(10000000):
sum_result += i
return sum_result
print(test_sum())
假设我想计算这个函数执行多久,则可以另外在定义一个计算时间的函数。
import time
def timer(func):
start_time = time.time()
func()
t = time.time() - start_time
print(f"当前函数执行时间是:{t}")
"""执行函数"""
timer(test_sum)
上述计时函数,如果在大量函数都需要计时的情况时,会有很多重复使用timer()调用。
此时我们可以使用python的装饰器概念,来实现简易操作。
代码如下:
import time
def timer(func):
def inner():
start_time = time.time()
result = func()
t = time.time() - start_time
print(f"当前函数执行时间是:{t}")
return result
return inner
"""这里用@加上定义的装饰器名称,即可以给函数动态加上装饰器内部定义的功能"""
@timer
def test_sum():
sum_result = 0
for i in range(1000000):
sum_result += i
return sum_result
print(test_sum())
执行结果:
当前函数执行时间是:0.0937497615814209
499999500000
Process finished with exit code 0
上述代码中有些缺陷,假设我的被装饰函数testsum以及其他被装饰函数需要入参时,且这些入参都不固定,则我们的装饰器中的inner函数需要重新优化一下。
import time
def timer(func):
"""此处,我们将内层函数的入参写成随意入参,则可以装饰不固定入参的函数"""
def inner(*args, **kwargs):
start_time = time.time()
result = func(*args, **kwargs)
t = time.time() - start_time
print(f"当前函数执行时间是:{t}")
return result
return inner
@timer
def test_sum():
sum_result = 0
for i in range(1000000):
sum_result += i
return sum_result
print(test_sum())
总结,我们可以直接记住装饰器的固定格式,因为这个装饰器的格式基本通用。
def 装饰器的名字(func):
def inner(*args, **kwargs):
"""此处是被装饰函数执行前需要的操作代码"""
result = func(*args, **kwargs)
"""此处是被装饰函数执行后需要的操作代码"""
return result
return inner
此时有个新的需要,假设我们的装饰器也需要入参时,则我们的装饰器2层嵌套需要变成3层嵌套使用了。
一般网上教程装饰器函数名称喜欢用decorator和wrapper。
举例,我们在计时完一个函数之后,需要再等待可以自定义的几秒。
import time
def timer(sleep_time):
def decorator(func):
def inner(*args, **kwargs):
start_time = time.time()
result = func(*args, **kwargs)
t = time.time() - start_time
print(f"当前函数执行时间是:{t}")
time.sleep(sleep_time)
return result
return inner
return decorator
@timer(sleep_time=10)
def test_sum():
sum_result = 0
for i in range(1000000):
sum_result += i
return sum_result
print(test_sum())
执行结果如下:
当前函数执行时间是:0.08781886100769043
499999500000
Process finished with exit code 0
我们看到在函数执行时间结果之后和计算结果出之前,停顿了10s。
此时我们引入一个新问题。
我们可以通过__name__属性来获取函数的名称。
def test_sum():
sum_result = 0
for i in range(1000000):
sum_result += i
return sum_result
print(test_sum.__name__)
执行结果为:test_sum
但是如果加上装饰器,就会变了。
import time
def timer(func):
def inner(*args, **kwargs):
start_time = time.time()
result = func(*args, **kwargs)
t = time.time() - start_time
print(f"当前函数执行时间是:{t}")
return result
return inner
@timer
def test_sum():
sum_result = 0
for i in range(1000000):
sum_result += i
return sum_result
print(test_sum.__name__)
执行结果是:inner
函数执行的__name__属性变成装饰器的内部函数行,如果有需要依赖的name属性时,就会导致错误。
此时我们可以用一个已经写好的装饰器,代码优化成如下:
import time
from functools import wraps
def timer(func):
"""此时会把name属性也改成需要被装饰的函数名称"""
@wraps(func)
def inner(*args, **kwargs):
start_time = time.time()
result = func(*args, **kwargs)
t = time.time() - start_time
print(f"当前函数执行时间是:{t}")
return result
return inner
@timer
def test_sum():
sum_result = 0
for i in range(1000000):
sum_result += i
return sum_result
print(test_sum.__name__)
综上所述,装饰器的标准格式代码成如下:
import time
from functools import wraps
def timer(sleeptime):
def decorator(func):
@wraps(func)
def inner(*args, **kwargs):
start_time = time.time()
result = func(*args, **kwargs)
t = time.time() - start_time
print(f"当前函数执行时间是:{t}")
time.sleep(sleeptime)
return result
return inner
return decorator
@timer(sleeptime=10)
def test_sum():
sum_result = 0
for i in range(1000000):
sum_result += i
return sum_result
print(test_sum())
print(test_sum.__name__)
本文地址:https://blog.csdn.net/weixin_43046974/article/details/107254532
上一篇: 浅谈Service中实现弹出对话框的坑
下一篇: 古诗文网登录