一、类装饰器
在Python中,装饰器是个非常强大且有用的工具,能改变或增强函数或类的行为。Python中的类装饰器就是对一个类进行装饰,以修改或增强这个类的一些行为。
普通的函数装饰器只接受一个函数,并返回一个函数,类装饰器接受一个类并返回一个类。
类装饰器的一个常见用途是提供类的一种初始化方式。以下是一个类装饰器的示例,它在类被定义时添加一个额外的方法:
def add_method(classObj):
classObj.extra_method = lambda self: "extra method was called"
return classObj
@add_method
class MyClass:
def __init__(self, name):
self.name = name
obj = MyClass("Test")
print(obj.extra_method()) # prints: extra method was called
在这个示例中,装饰器add_method添加了一个新的方法extra_method到类MyClass上。所以当我们创建MyClass的新实例并调用extra_method时,将会返回字符串"extra method was called"。
这只是类装饰器的一个简单示例,类装饰器可以用于执行各种有趣和有用的任务,如做一些预处理、后处理工作,增加新的方法或属性,甚至可以改变类的行为。
二、函数装饰器
在Python中,函数装饰器是一个非常强大的工具,它可以修改一个函数的行为。基本形式如下:
def my_decorator(func):
def wrapper():
# 在函数执行前做一些事
func()
# 在函数执行后做一些事
return wrapper
@my_decorator
def my_function():
pass
在这里,my_decorator就是一个装饰器。其基本思想就是,当你这样的调用一个函数:@my_decorator,你实际上是在执行 my_function = my_decorator(my_function)。
装饰器的一种常见用法是在函数执行前后插入日志代码:
def log_decorator(func):
def wrapper(*args, **kwargs):
print(f"Before calling {func.__name__}")
result = func(*args, **kwargs)
print(f"After calling {func.__name__}")
return result
return wrapper
@log_decorator
def say_hello():
print("Hello")
say_hello()
在这个示例中,我们有一个log_decorator装饰器,它在函数调用前后打印一条消息。我们使用 @log_decorator 修饰 say_hello 函数,该函数的行为被修改为:在打印 "Hello" 之前和之后,分别打印 "Before calling say_hello " 和 "After calling say_hello "。
三、带参数的装饰器
Python中的装饰器可以带参数,这种装饰器也称为"参数化装饰器"。参数化装饰器可以在声明时接受额外的参数,这些参数可以用来控制装饰器的行为。
带参数的装饰器实际上是一个装饰器的工厂函数,它返回一个装饰器,然后这个装饰器去装饰目标函数。所以带参数的装饰器需要三层嵌套的函数。
以下是一个简单的带参数的装饰器例子:
def repeat(num_times):
def decorator_repeat(func):
def wrapper(*args, **kwargs):
for _ in range(num_times):
result = func(*args, **kwargs)
return result
return wrapper
return decorator_repeat
# 使用
@repeat(num_times=4)
def greet(name):
print(f"Hello {name}")
greet("World") # 输出 "Hello World" 4次
在这个例子中,repeat(num_times=4) 会返回一个装饰器 decorator_repeat,然后 decorator_repeat 去装饰函数 greet。
这样,我们便可以控制 greet 函数被调用的次数,把次数作为参数传给装饰器 repeat。
四、装饰器链
Python 装饰器可以"链式"使用,就是说你可以同时将多个装饰器应用到一个函数上。使用装饰器链时,应用的顺序会影响结果。
装饰器在应用时,离函数最近的装饰器会被首先应用,然后依此向上应用其他的装饰器。
看一个简单的示例:
def decorator1(func):
def wrapper1():
print("Decorator1 before call")
func()
print("Decorator1 after call")
return wrapper1
def decorator2(func):
def wrapper2():
print("Decorator2 before call")
func()
print("Decorator2 after call")
return wrapper2
@decorator1
@decorator2
def hello():
print("Hello")
hello()
在这个示例中,我们有两个装饰器 decorator1 和 decorator2,且都应用到了 hello 函数上。当调用 hello 函数时,会看到如下打印结果:
Decorator1 before call
Decorator2 before call
Hello
Decorator2 after call
Decorator1 after call
可以看到,先应用的装饰器是离函数更近的装饰器 decorator2,然后才是装饰器 decorator1。所以我们可以得出结论:在装饰器链中,装饰器的执行顺序是从最近的函数开始,依次向上执行。