本文最后更新于 197 天前,其中的信息可能已经有所发展或是发生改变。
定义一个函数,这个函数的功能就是用来装饰其他函数的(给其它函数添加额外的功能)
例子1
#装饰器例子
####装饰器代码###写在语法糖前
@outer #语法糖 相当于inside = outer(inside)
import time
def inside(group,s):
print('欢迎来到王者荣耀')
print(f'你出生在{group}方')
print(f'敌军还有{s}秒到达战场')
time.sleep(s)
print('全军出击!')
return 100
print('原inside的内存地址',inside)
#需求:在不改变上面代码的基础上增加一个统计程序运行时间的功能
#当源代码需要传递新的参数时也不需要修改修饰器的内容
def outer(func): #装饰什么功能,就将什么功能的内存地址传递给outer
# func = inside #inside 存的是内存地址
def total_time(*args,**kwargs): #当原函数需要新传递一个参数z时,可以不用修改代码,在调用时直接传入,在*args和**kwargs的功能下自动传递打散
start = time.time()
response = func(*args,**kwargs) #对原函数的调用 ,为了不将所修饰的函数写死,将inside变为可变参数
end = time.time()
print('程序运行了 {} 秒: '.format(end-start))
return response #当需要修饰的功能有返回值时,将返回值保存在response中再返回出来,伪装需要修饰的功能
return total_time #返回total_time 的内存地址,依据闭包函数的原理,便于在后面掉用在其它函数内部的total_time函数(即在全局拿到total_time这个函数内存地址,即outer的返回值)
# total_time('红色', 3) #对原函数的调用变为调用装饰器实现
inside = outer(inside) #inside就相当于total_time功能 在不修改原inside的基础上,新的inside覆盖了原inside的内存地址,实现了修饰功能
print('新inside的内存地址',inside)
res = inside('红色',3) #依照inside的参数来传参
print(res)
原inside的内存地址 <function inside at 0x0000018649A4A940>
新inside的内存地址 <function outer.<locals>.total_time at 0x0000018649925CA0>
欢迎来到王者荣耀
你出生在红色方
敌军还有3秒到达战场
全军出击!
程序运行了 3.0062177181243896 秒:
100
例子2
# 显示充电情况
@outer
def recharge(num):
for i in range(0,101):
time.sleep(0.05)
print(f'\r当前电量为{"▍"*i} {i}%',end='') #\r 表示覆盖当前内容
print('\n充电完成!')
return 10
# recharge(5)
#使用上述修饰器total_time 修饰
#recharge = outer(recharge) #已有语法糖
res = recharge(5)
print(res) #取得原函数的返回值
当前电量为▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍ 100%
充电完成!
程序运行了 6.271658658981323 秒:
10
无参装饰器模板
#装饰器模板
def outer(func):
def wrapper(*args,**kwargs):
# start
res = func(*args,**kwargs) #原函数调用
# end
return res
return wrapper
有参装饰器模板
#有参装饰器模板
def g_outer(x)
def outer(func):
def wrapper(*args,**kwargs):
# start
res = func(*args,**kwargs) #原函数调用
# end
return res
return wrapper
return outer
例子3
#当装饰器outer需要传递一个新的参数时如name,就需要在外部再包装一层函数
import time
from functools import wraps #wraps 是一个装饰器,用来把原函数所有的属性都赋值给新的装饰器
def g_outer(name):
def outer(func):
@wraps(func) # recharge = 原函数的内存地址.__name__ # recharge = 原函数的内存地址.__doc__ 用于实现完美伪装
def total_time(*args,**kwargs):
start = time.time()
response = func(*args,**kwargs)
end = time.time()
print('程序运行了 {} 秒: '.format(end-start))
print(name) #装饰器中需要的新功能
return response
return total_time
return outer
@g_outer('nb') # recharge = outer(recharge) 将语法糖outer改为g_outer(name)当成语法糖来使用,就实现了有参装饰器的功能
def recharge(num):
for num in range(num,101):
time.sleep(0.05)
print(f'\r当前电量为{num}%',end='')
print('\n充电完成!')
return 10
res = recharge(50)
print(res)
New
1. @property装饰器,相当于一个get方法,用于获取私有属性值,
2. setter方法, 用于访问和修改对象的私有属性。python对于setter装饰器的语法是:@方法名.setter,
3. deleter 装饰器用来删除指定属性,用法: @方法名.deleter
4. 缓存装饰器一 : @cache
相比@lru_cache, @cache 装饰器更轻量化,速度更快,且是线程安全,不同线程可以调用同1个函数,缓存值可以共享。
5. 缓存装饰器二 : @lru_cache
属于functools模块 ,LRU(Least Recently Used),当缓存队列已满时,将缓存使用次数最少的元素从队列中移除,将新元素加入队列。
@functools.lru_cache(maxsize=128, typed=False)
其中maxsize为最大缓存数量,默认为128。None则无限制。
typed=True时不同参数类型的调用将分别缓存,默认False
6.缓存装饰器三 :@cached_property
@cached_property
是一个装饰器,它将类的方法转换为属性,其值仅计算一次,然后缓存为普通属性。因此,只要实例持久存在,缓存的结果就可用,我们可以将该方法用作类的属性那样来使用,如
调用: : instance.method
取代旧方式 : instance.method()
@cached_property
是 Python 中 functools 模块的一部分。
它类似于 property()
,但 @cached_property
带有一个额外的功能,那就是缓存。