目录
目录
一 介绍
装饰器(Decorators)是 Python 的一个重要部分。简单地说:他们是修改其他函数的功能的函数(与java的注释类似)。他们有助于让我们的代码更简短,也更Pythonic(Python范儿)。
装饰器的本质:在不改变被装饰对象原有的“调用方式”和“内部代码”的情况下给被装饰对象添加新的功能。原则就是对扩展开放,对修改封闭
使用场景
-
AOP切面
-
日志
-
权限拦截
-
HTTP请求
-
数据处理
1 简单实现装饰器
def my_decorator(func):
def wrapper(*args, **kwargs):
print("before the function is called.")
func(*args, **kwargs)
print("after the function is called.")
return 'wrapper msg'
return wrapper # 目标函数需要接收参数
-
*args, **kwargs 获取所有参数进行赋值
-
目标返回值是wrapper函数中return
普通调用
def say_whee():
print("Whee!")
say_whee = my_decorator(say_whee) # 定义一个装饰方法
say_whee('李',c='18',b='20') # 'wrapper msg'
糖语法
在python中使用@符号可以定义一个修饰后的函数
@my_decorator
def say_whee():
print("Whee!")
say_whee('李',c='18',b='20') # 'wrapper msg'
2 进阶
简单版的目标函数可以接收参数,但装饰器需要接收参数,解决办法是在最外层再加一个匿名函数
# logParam 装饰器实现,如果装饰多层,函数名与会变
def logParam(level): # 最外层函数,可以接收参数给装饰器使用
def outer(func):
@functools.wraps(func) # 该方法解决返回的方法是wrapper,而不是目标方法
def wrapper(*args, **kwargs):
funName = func.__name__ # 如果不加@functools.wraps(func),该函数名第二次会是wrapper
match level:
case 'info':
print(f'[INFO] 方法名:{funName},参数{args} - {kwargs}')
case 'error':
print(f'[ERROR] 方法名:{funName},参数{args} - {kwargs}')
case 'debug':
print(f'[DEBUG] 方法名:{funName},参数{args} - {kwargs}')
func(*args, **kwargs)
return wrapper # 目标函数需要接收参数
return outer # 需要装饰的目标
普通调用
# 普通调用
def my(name, age):
print(f'名字:{name},年纪:{age}')
# 装饰1层
iwap = logParam('info')
themy = iwap(my)
# 装饰2层
ewap = logParam('error')
thewap = ewap(themy)
# 调用
thewap('李零山',18)
糖语法
@logParam('debug')
@logParam('error')
@logParam('info')
def my(name, age):
print(f'名字:{name},年纪:{age}')
my('李零山',age = 18)
# 执行顺序 debug -> error -> info -> my
3 装饰类
python可以类中进行装饰,以下是单例模式示例:
import functools
def singleton(cls):
@functools.wraps(cls)
def wrapper_singleton(*args, **kwargs):
if not wrapper_singleton.instance:
wrapper_singleton.instance = cls(*args, **kwargs)
return wrapper_singleton.instance
wrapper_singleton.instance = None
return wrapper_singleton
@singleton
class TheOne:
pass
to = TheOne()
二 内置修饰器
1 类装饰器
-
@abstractmethod 定义一个抽象方法,子类实现了该抽象方法才能被实例化。
-
@classmethod 声明方法为类方法,同过类名.方法()可以直接调用
-
@staticmethoed 声明方法为静态方法,同过类名.方法()可以直接调用
-
@property 把类的方法伪装成属性
-
只读不可修改的属性
-
输入对setter进行判断
-
需要实时地计算属性值
-
-
@price.setter 属性设定,可以用来限制属性的范围等等。
-
@price.deleter 定义属性的删除,在del house.price时被执行
2 其他修饰器,可以参考官网文档