装饰器是一种在『不修改原函数代码』的前提下,对函数进行『增强』的工具。它是Python中非常强大的语法特性,常用于:日志、校验、计时、缓存、权限控制等。
核心语法:装饰器是一种可调用对象(通常是函数),接收一个函数作为参数,并返回一个函数。
通常分为两个类型:函数装饰器、类装饰器。下面详细介绍。
需求:在不修改
add函数的前提下,给add函数增加一些额外的功能,例如:计算前打印一句欢迎语。
1️⃣定义函数装饰器
def say_hello(func):
def wrapper(*args, **kwargs):
print("你好,我要开始计算了")
return func(*args, **kwargs)
return wrapper
定义装饰器核心规则:
2️⃣使用函数装饰器(手动装饰)
def add(a, b, c):
res = a + b + c
print(f'{a}和{b}和{c}相加的结果是:{res}')
return res
# 调用 say_hello 装饰器,对 add 函数进行装饰,并得到装饰后的新函数
add = say_hello(add)
result = add(1, 2, 3)
print(result)
上述代码运行结果:
你好,我要开始计算了
1和2和3相加的结果是:6
6
3️⃣使用函数装饰器(语法糖@)
@say_hello
def add(a, b, c):
res = a + b + c
print(f'{a}和{b}和{c}相加的结果是:{res}')
return res
result = add(1, 2, 3)
print(result)
上述代码运行结果:
你好,我要开始计算了
1和2和3相加的结果是:6
6
上述代码的执行流程:
➀
@say_hello会自动执行:add = say_hello(add)。➁ 以后调用
add()时,真正执行的是wrapper()。
4️⃣带参数的函数装饰器(三层嵌套)
需求:装饰不同的函数,打印不同的欢迎语。
核心:带参数的装饰器最终是三层嵌套:外层接收配置、中间层接收函数、内层接收具体参数。
def calculate(msg):
def outer(func):
def wrapper(*args, **kwargs):
print(f'你好,我要开始{msg}计算了')
return func(*args, **kwargs)
return wrapper
return outer
# 装饰加法函数
@calculate('加法')
def add(a, b, c):
res = a + b + c
print(f'{a}和{b}和{c}相加的结果是:{res}')
return res
# 装饰减法函数
@calculate('减法')
def sub(a, b):
res = a - b
print(f'{a}和{b}相减的结果是:{res}')
return res
result = add(1, 2, 3)
print(result)
print()
result1 = sub(4, 5)
print(result1)
上述代码运行结果如下:
你好,我要开始加法计算了
1和2和3相加的结果是:6
6
你好,我要开始减法计算了
4和5相减的结果是:-1
-1
5️⃣多个函数装饰器一起使用
核心:注意装饰顺序,距离函数最近的装饰器,会先工作。
例如下面的代码:test2先装饰,test1再装饰。
def decorator1(func):
print('我是decorator1装饰器')
def wrapper(*args, **kwargs):
res = func(*args, **kwargs)
print('decorator1追加的逻辑')
return res
return wrapper
def decorator2(func):
print('我是decorator2装饰器')
def wrapper(*args, **kwargs):
res = func(*args, **kwargs)
print('decorator2追加的逻辑')
return res
return wrapper
@decorator1
@decorator2
def add(a, b, c):
res = a + b + c
print(f'{a}和{b}和{c}相加的结果是:{res}')
return res
result = add(1, 3, 4)
print(result)
上述代码运行结果如下:
我是decorator2装饰器
我是decorator1装饰器
1和3和4相加的结果是:8
decorator2追加的逻辑
decorator1追加的逻辑
8
包含__call__方法的类,就是类装饰器。
像调用函数一样,去调用类装饰器的实例对象,就会触发__call__方法的调用。
__call__方法通常接收一个函数作为参数,并且会返回一个新函数。
1️⃣定义类装饰器
需求和之前一样,还是给add函数增加【打印欢迎语】的功能。
class SayHello:
def __call__(self, func):
def wrapper(*args, **kwargs):
print('你好,我要开始计算了')
return func(*args, **kwargs)
return wrapper
2️⃣使用类装饰器(手动装饰)
手动使用类装饰器的流程:先创建类的实例对象,随后调用实例对象,并传入要装饰的函数。
# 定义被装饰函数
def add(x, y):
res = x + y
print(f'{x}和{y}相加的结果是{res}')
return res
# 使用 SayHello 去装饰 add 函数(手动装饰)
say_hello_inst = SayHello()
add_decorator = say_hello_inst(add)
# 调用装饰后的函数
result = add_decorator(10, 20)
print(result)
# 运行结果如下:
# 你好,我要开始计算了
# 10和20相加的结果是30
# 30
3️⃣使用类装饰器(语法糖@)
注意:通过<font style="color:#DF2A3F;">语法糖@</font>使用装饰器时,类名后要加圆括号调用。
@SayHello()
def add(x, y):
res = x + y
print(f'{x}和{y}相加的结果是{res}')
return res
# 直接调用被装饰的函数 add,但调用的是被装饰后的新函数
result = add(1, 2)
print(result)
# 运行结果如下:
# 你好,我要开始计算了
# 1和2相加的结果是3
# 3
4️⃣带参数的类装饰器(三层嵌套)
带参数的类装饰器写起来,要比带参数的函数装饰器简单,不需要三层结构。
class SayHello:
def __init__(self, msg):
self.msg = msg
def __call__(self, func):
def wrapper(*args, **kwargs):
print(f'你好,我要开始{self.msg}计算了')
return func(*args, **kwargs)
return wrapper
@SayHello('加法')
def add(x, y):
res = x + y
print(f'{x}和{y}相加的结果是{res}')
return res
# 直接调用被装饰的函数 add,但调用的是被装饰后的新函数
result = add(1, 2)
print(result)
# 运行结果如下:
# 你好,我要开始加法计算了
# 1和2相加的结果是3
# 3
5️⃣多个类装饰器一起使用
class SayHello:
def __init__(self, msg):
self.msg = msg
def __call__(self, func):
def wrapper(*args, **kwargs):
print(f'你好,我要开始{self.msg}计算了')
return func(*args, **kwargs)
return wrapper
class Helper:
def __call__(self, func):
def wrapper(*args, **kwargs):
print('相信我,绝对可以的')
return func(*args, **kwargs)
return wrapper
@SayHello('加法')
@Helper()
def add(x, y):
res = x + y
print(f'{x}和{y}相加的结果是{res}')
return res
# 直接调用被装饰的函数 add,但调用的是被装饰后的新函数
result = add(1, 2)
print(result)
🔥BuildAdmin是一个永久免费开源,无需授权即可商业使用,且使用了流行技术栈快速创建商业级后台管理系统。