前言
本章内容主要是介绍装饰器相关的知识:
装饰器是Python中一种特殊的函数,用于修改其他函数的行为。它可以在不修改原始函数代码的情况下添加额外的功能。
一、知识回顾
在介绍装饰器之前,回顾装饰器所需要的三个知识点:
- 函数可以作为参数进行传递
def func():
print("我是函数")
def gg(fn): # fn是参数也是函数
gg(func)
我是函数
- 函数可以作为返回值进行返回
def func():
def inner():
print("123")
return inner
ret = func() # 此时ret()就是inner()
ret()
123
- 函数名称可以当成变量一样进行赋值操作
def func1():
print("我是函数1")
def func2():
print("我是函数2")
func1 = func2
func1()
我是函数2
回顾并理解了这三个知识点,理解装饰器就会变得很简单
二、装饰器的语法
装饰器是一个函数,它接受一个函数作为参数,并返回另一个函数。通常情况下,装饰器使用 @
符号以及装饰器函数的名称来修饰目标函数。
装饰器其实本质上是一个闭包,参数为局部变量,但是该局部参数为函数。
"""
定义两个”游戏“函数
"""
def DNF():
print("你好啊,我叫赛利亚,今天又是美好的一天!")
def LOL():
print("德玛西亚!!!")
"""
现在我想给我的游戏开个”外挂“
"""
print("打开外挂")
DNF() # 启动游戏DNF
print("关闭外挂")
print("打开外挂")
LOL() # 启动游戏LOL
print("关闭外挂") # 每次打游戏都需要手动打开外挂,很烦。让管家帮我
def guanjia(game):
def inner():
print("打开外挂")
game()
print("关闭外挂")
return inner
DNF = guanjia(DNF)
LOL = guanjia(DNF)
"现在就可以玩儿外挂游戏了,但是我可以直接把我的游戏改成自带外挂的游戏,把我的游戏@guanjia封装一下。"
ef guanjia(game):
def inner():
print("打开外挂")
game()
print("关闭外挂")
return inner
@guanjia
def DNF():
print("你好啊,我叫赛利亚,今天又是美好的一天!")
@guanjia
def LOL():
print("德玛西亚!!!")
DNF()
LOL()
打开外挂
你好啊,我叫赛利亚,今天又是美好的一天!
关闭外挂
打开外挂
德玛西亚!!!
关闭外挂
三、装饰器的参数传递
带参数的装饰器是指可以接受参数的装饰器函数。通过在装饰器函数外再包一层函数,这个外层函数用来接受参数,并返回装饰器函数。这样可以根据传入的参数来定制装饰器的行为,使得装饰器具有更大的灵活性和可定制性。
def repeat(n):
def decorator(func):
def wrapper(*args, **kwargs):
for _ in range(n):
result = func(*args, **kwargs)
return result
return wrapper
return decorator
@repeat(n=3)
def greet(name):
print(f"Hello, {name}!")
greet("Alice")
在这个示例中,repeat
函数是一个带参数的装饰器。它接受一个参数n,表示重复执行目标函数的次数。在装饰器内部,定义了一个decorator
函数作为装饰器函数,它接受目标函数func作为参数,并返回一个新的函数wrapper。在wrapper
函数内部,利用for循环执行目标函数func
,重复n次。
通过使用@repeat(n=3)
语法,我们将repeat装饰器应用到greet函数上,并传入参数n=3。这样,greet函数在被调用时会重复打印Hello, Alice!三次。
这种带参数的装饰器可以用于很多场景,例如重试机制、缓存设置等,通过传入不同的参数可以实现不同的功能定制。
四、装饰器的嵌套
装饰器可以进行嵌套,即一个装饰器可以包含另一个装饰器。在使用多个装饰器修饰同一个函数时,装饰器的调用顺序是由内向外的。
举个例子,我们定义了两个装饰器函数make_bold
和make_italic
,它们分别用来给文本加粗和加斜体标签。然后,我们在gree
t函数上应用了这两个装饰器,实现了对greet
函数返回值的同时加粗和加斜体处理。
当调用greet()函数时,实际上是调用了经过两个装饰器装饰后的wrapper
函数。首先,make_italic
装饰器将greet
函数包裹在了一个带有斜体标签的wrapper
函数中,然后make_bold
装饰器又将这个斜体文本包裹在了一个带有粗体标签的wrapper
函数中。最终的效果是,打印出来的文本既有斜体又有粗体效果。
def make_bold(func):
def wrapper():
return "<b>" + func() + "</b>"
return wrapper
def make_italic(func):
def wrapper():
return "<i>" + func() + "</i>"
return wrapper
@make_bold
@make_italic
def greet():
return "Hello, world!"
print(greet())
五、类装饰器
class MyDecorator:
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
print("Something is happening before the function is called.")
result = self.func(*args, **kwargs)
print("Something is happening after the function is called.")
return result
@MyDecorator # 应用类装饰器
def say_hello(name):
print(f"Hello, {name}!")
say_hello("Charlie") # 调用被装饰的函数
MyDecorator
是一个类装饰器,它接受一个函数func
作为参数并在__call__
方法中执行额外操作。- 使用
@MyDecorator
应用类装饰器,它将包装say_hello
方法,使其在调用前后执行额外操作。