Python 装饰器详解
装饰器(Decorator)是 Python 中的一种强大且灵活的功能,它允许在不修改原始函数或类代码的前提下,向其添加额外的功能。装饰器本质上是一个函数,它接受一个函数或类作为参数,并返回一个增强版的函数或类。本文将详细介绍装饰器的概念、使用方式,以及如何创建和应用函数装饰器和类装饰器。
1. 函数装饰器(Function Decorators)
函数装饰器是最常见的一种装饰器,它允许我们在不修改函数代码的情况下,给函数增加额外的功能。
1.1 基本语法
一个装饰器函数接受一个函数作为参数,并返回一个增强版的函数。装饰器通常通过 @decorator_name
的语法应用于函数。
装饰器的基本示例
python
def my_decorator(func):
def wrapper():
print("Before function call")
func()
print("After function call")
return wrapper
# 使用装饰器
@my_decorator
def say_hello():
print("Hello, World!")
say_hello()
输出:
Before function call
Hello, World!
After function call
在这个例子中,my_decorator
是一个装饰器,它在调用 say_hello()
之前和之后分别打印一些信息。
1.2 带参数的装饰器
如果装饰器需要处理有参数的函数,我们可以通过修改 wrapper
函数来实现这一点。装饰器可以接受任意数量的位置和关键字参数,并将它们传递给原始函数。
python
def my_decorator(func):
def wrapper(*args, **kwargs):
print("Before function call")
result = func(*args, **kwargs)
print("After function call")
return result
return wrapper
@my_decorator
def greet(name):
print(f"Hello, {name}!")
greet("Alice")
输出:
Before function call
Hello, Alice!
After function call
1.3 functools.wraps
的使用
当我们使用装饰器时,原函数的一些元数据(如文档字符串、函数名称等)会丢失。为了保留这些信息,我们可以使用 functools.wraps
来确保装饰器返回的 wrapper
函数继承原始函数的元数据。
python
import functools
def my_decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
print("Before function call")
result = func(*args, **kwargs)
print("After function call")
return result
return wrapper
@my_decorator
def greet(name):
"""Greets the person by name."""
print(f"Hello, {name}!")
print(greet.__name__) # 输出: greet
print(greet.__doc__) # 输出: Greets the person by name.
通过使用 @functools.wraps(func)
,我们确保了装饰器不会丢失原始函数的名称和文档字符串。
2. 类装饰器(Class Decorators)
除了函数装饰器,Python 还支持类装饰器,它允许我们对类进行修改或扩展。类装饰器的工作原理与函数装饰器相似,不同的是它们处理的是类,而不是函数。
2.1 基本语法
类装饰器是一个函数,接受一个类作为参数,并返回一个修改后的类。类装饰器可以用来增强类的功能或修改其行为。
类装饰器示例
python
def class_decorator(cls):
class NewClass(cls):
def greet(self):
return f"Hello, {self.name}!"
return NewClass
@class_decorator
class Person:
def __init__(self, name):
self.name = name
p = Person("Alice")
print(p.greet()) # 输出: Hello, Alice!
在这个例子中,class_decorator
装饰器接受 Person
类,返回一个新的类 NewClass
,它在原始类的基础上添加了一个 greet
方法。
2.2 修改类的属性和方法
类装饰器不仅可以增加新方法,还可以修改现有的方法或属性。下面的示例展示了如何通过装饰器修改类的构造函数。
python
def add_age(cls):
original_init = cls.__init__
def new_init(self, name, age):
original_init(self, name)
self.age = age
cls.__init__ = new_init
return cls
@add_age
class Person:
def __init__(self, name):
self.name = name
p = Person("Bob", 30)
print(p.name) # 输出: Bob
print(p.age) # 输出: 30
在这个例子中,add_age
装饰器修改了 Person
类的构造函数,添加了一个 age
属性。
3. 装饰器的实际应用
装饰器在实际开发中有许多应用场景,例如:
- 日志记录:记录函数的调用日志。
- 权限控制:检查用户是否有权限执行某些操作。
- 性能分析:计算函数执行的时间。
- 缓存:缓存函数的返回结果,提高效率。
3.1 日志装饰器
python
def log_function_call(func):
def wrapper(*args, **kwargs):
print(f"Calling {func.__name__} with arguments {args} and {kwargs}")
return func(*args, **kwargs)
return wrapper
@log_function_call
def add(a, b):
return a + b
add(2, 3)
输出:
Calling add with arguments (2, 3) and {}
3.2 性能分析装饰器
python
import time
def timer(func):
def wrapper(*args, **kwargs):
start = time.time()
result = func(*args, **kwargs)
end = time.time()
print(f"Function {func.__name__} executed in {end - start:.4f} seconds")
return result
return wrapper
@timer
def slow_function():
time.sleep(2)
slow_function()
输出:
Function slow_function executed in 2.0001 seconds
4. 总结
装饰器是 Python 中非常强大且灵活的功能,能够动态地修改函数或类的行为。它广泛应用于日志记录、权限验证、性能分析、缓存等场景。我们可以通过简单的 @decorator
语法来实现装饰器,使用装饰器时需注意保留函数的元数据,可以借助 functools.wraps
来实现。类装饰器与函数装饰器类似,允许我们动态地修改类的行为和属性。
掌握装饰器的使用,不仅能让你的代码更具灵活性,还能提高代码的可读性和可维护性。