在 Python 编程领域,装饰器是一项功能强大且灵活的特性,它能在不修改原有函数或类代码的基础上,动态地为它们添加新功能。通过丰富的代码示例,深入学习 Python 装饰器知识,方便日后复习回顾。
一、装饰器基础概念
1.1 装饰器的定义
装饰器本质上是一个函数,它以另一个函数作为参数,并返回一个新函数或对原函数进行修改。在 Python 中,使用@decorator_name
语法将装饰器应用到函数或方法上。例如:
def decorator_function(original_function):
def wrapper():
print("在原函数执行前添加的操作")
original_function()
print("在原函数执行后添加的操作")
return wrapper
@decorator_function
def target_function():
print("这是原函数的操作")
target_function()
在上述代码中,decorator_function
是装饰器函数,它接受target_function
作为参数,并返回wrapper
函数。@decorator_function
语法将target_function
传递给decorator_function
,之后调用target_function
时,实际调用的是wrapper
函数,从而实现了在原函数前后添加额外操作的功能。运行代码后,输出结果为:
在原函数执行前添加的操作
这是原函数的操作
在原函数执行后添加的操作
1.2 装饰器的工作原理
当使用@decorator_name
装饰函数时,Python 会自动将被装饰的函数作为参数传递给装饰器函数,装饰器函数返回的新函数会替换原来的函数。可以将这个过程理解为:
def target_function():
print("这是原函数的操作")
target_function = decorator_function(target_function)
这种机制使得装饰器能够在不改变原函数代码的情况下,对函数的行为进行扩展。
二、装饰器的应用场景
2.1 日志记录
在函数执行前后记录相关信息,方便调试和追踪。例如:
def log_function_call(func):
def wrapper(*args, **kwargs):
print(f"调用函数 {func.__name__},参数为:{args}, {kwargs}")
result = func(*args, **kwargs)
print(f"函数 {func.__name__} 执行完毕,返回值为:{result}")
return result
return wrapper
@log_function_call
def add_numbers(a, b):
return a + b
add_numbers(3, 5)
运行代码后,会输出函数调用和返回的相关信息:
调用函数 add_numbers,参数为:(3, 5), {}
函数 add_numbers 执行完毕,返回值为:8
2.2 性能分析
测量函数的执行时间,用于优化代码性能。例如:
import time
def measure_time(func):
def wrapper(*args, **kwargs):
start_time = time.time()
result = func(*args, **kwargs)
end_time = time.time()
print(f"函数 {func.__name__} 执行时间为:{end_time - start_time} 秒")
return result
return wrapper
@measure_time
def complex_calculation():
time.sleep(2) # 模拟复杂计算
return 42
complex_calculation()
运行代码后,会输出函数的执行时间:
函数 complex_calculation 执行时间为:2.000000 秒(实际输出的时间会因系统差异略有不同)
2.3 权限控制
限制对某些函数的访问权限。例如:
def check_permission(func):
def wrapper():
# 假设这里通过某种方式检查权限,比如判断用户是否登录
is_logged_in = True # 模拟登录状态
if is_logged_in:
return func()
else:
print("权限不足,无法访问该函数")
return wrapper
@check_permission
def sensitive_operation():
print("执行敏感操作")
sensitive_operation()
如果is_logged_in
为False
,运行代码后会输出 “权限不足,无法访问该函数”;为True
时,则正常执行函数。
三、装饰器的不同形式
3.1 带参数的装饰器
装饰器不仅可以装饰带参数的函数,自身也可以接受参数。例如:
def repeat(num_times):
def decorator(func):
def wrapper(*args, **kwargs):
for _ in range(num_times):
func(*args, **kwargs)
return wrapper
return decorator
@repeat(3)
def say_hello():
print("Hello!")
say_hello()
这里repeat
是一个装饰器工厂函数,它接受num_times
参数,返回一个装饰器decorator
。@repeat(3)
表示将say_hello
函数重复执行 3 次,运行代码后会输出 3 次 “Hello!”。
3.2 类装饰器
类也可以作为装饰器使用,通过定义__call__
方法来实现。例如:
class ClassDecorator:
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
print("在类装饰器中,执行原函数前的操作")
result = self.func(*args, **kwargs)
print("在类装饰器中,执行原函数后的操作")
return result
@ClassDecorator
def decorated_function():
print("这是被类装饰器装饰的函数")
decorated_function()
在上述代码中,ClassDecorator
类作为装饰器,当调用decorated_function
时,会执行ClassDecorator
类中__call__
方法里的额外操作,输出结果为:
在类装饰器中,执行原函数前的操作
这是被类装饰器装饰的函数
在类装饰器中,执行原函数后的操作
3.3 多个装饰器堆叠
多个装饰器可以堆叠使用,它们按照从下到上的顺序依次应用。例如:
def decorator1(func):
def wrapper():
print("Decorator 1 执行前")
func()
print("Decorator 1 执行后")
return wrapper
def decorator2(func):
def wrapper():
print("Decorator 2 执行前")
func()
print("Decorator 2 执行后")
return wrapper
@decorator1
@decorator2
def target():
print("这是目标函数")
target()
运行代码后,输出结果为:
Decorator 1 执行前
Decorator 2 执行前
这是目标函数
Decorator 2 执行后
Decorator 1 执行后
四、Python 内置装饰器
4.1 @staticmethod
将方法定义为静态方法,不需要实例化类即可调用。例如:
class MyClass:
@staticmethod
def static_method():
print("这是一个静态方法")
MyClass.static_method()
运行代码后,直接通过类名调用static_method
方法,输出 “这是一个静态方法”。
4.2 @classmethod
将方法定义为类方法,第一个参数是类本身(通常命名为cls
)。例如:
class MyClass:
@classmethod
def class_method(cls):
print(f"这是 {cls.__name__} 的类方法")
MyClass.class_method()
运行代码后,同样通过类名调用class_method
方法,输出 “这是 MyClass 的类方法”。
4.3 @property
将方法转换为属性,使其可以像属性一样访问。例如:
class MyClass:
def __init__(self):
self._name = ""
@property
def name(self):
return self._name
@name.setter
def name(self, value):
self._name = value
obj = MyClass()
obj.name = "Alice"
print(obj.name)
在上述代码中,通过@property
装饰器将name
方法转换为属性,实现了像访问属性一样访问和设置name
的值。
五、总结
Python 装饰器为代码的功能扩展提供了一种优雅且高效的方式,无论是日志记录、性能分析、权限控制,还是与内置装饰器的结合使用,都能显著提升代码的质量和可维护性。通过深入学习装饰器的原理、应用场景和不同形式,在实际编程中可以根据需求灵活运用,编写出更加简洁、健壮的代码。希望这篇博客能帮助你更好地复习和巩固 Python 装饰器的知识,在编程实践中充分发挥其优势。