装饰器是 Python 中一个非常强大和灵活的特性,用于修改或扩展函数或方法的行为。装饰器本质上是一个高阶函数,它可以接受一个函数作为参数,并返回一个新的函数。装饰器通常用于日志记录、性能测试、事务处理、缓存、权限校验等场景。
基本概念
高阶函数:接受一个或多个函数作为输入,或者输出一个函数的函数。
闭包:一个函数对象,记住了它被定义时的自由变量的值。
基本装饰器
定义装饰器
装饰器通常定义为一个外层函数,这个外层函数返回一个内层函数。内层函数负责执行实际的装饰逻辑。
def my_decorator(func):
def wrapper():
print("Something is happening before the function is called.")
func()
print("Something is happening after the function is called.")
return wrapper
@my_decorator
def say_hello():
print("Hello!")
say_hello()
装饰器的工作原理
@符号:@decorator 是装饰器的语法糖,等价于 say_hello = my_decorator(say_hello)。
调用过程:
say_hello 被传递给 my_decorator。
my_decorator 返回 wrapper 函数。
say_hello 现在指向 wrapper 函数。
当调用 say_hello() 时,实际上是调用 wrapper()。
带参数的装饰器
有时候,我们希望装饰器本身也能接受参数。这可以通过再嵌套一层函数来实现。
def repeat(num_times):
def decorator(func):
def wrapper(*args, **kwargs):
for _ in range(num_times):
result = func(*args, **kwargs)
return result
return wrapper
return decorator
@repeat(3)
def greet(name):
print(f"Hello, {name}!")
greet("Alice")
保留元数据
使用装饰器后,原始函数的元数据(如名称、文档字符串等)会被覆盖。为了保留这些元数据,可以使用 functools.wraps。
import functools
def my_decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
print("Something is happening before the function is called.")
result = func(*args, **kwargs)
print("Something is happening after the function is called.")
return result
return wrapper
@my_decorator
def say_hello():
"""Say hello to the user."""
print("Hello!")
print(say_hello.__name__) # 输出: say_hello
print(say_hello.__doc__) # 输出: Say hello to the user.
类装饰器
除了函数装饰器,Python 还支持类装饰器。类装饰器通常用于修改类的行为。
def add_class_method(cls):
def decorator(func):
setattr(cls, func.__name__, func)
return cls
return decorator
@add_class_method
class MyClass:
pass
def say_hello(self):
print("Hello from MyClass!")
instance = MyClass()
instance.say_hello() # 输出: Hello from MyClass!
装饰器组合
可以将多个装饰器应用于同一个函数。装饰器的执行顺序是从内到外。
def decorator1(func):
def wrapper():
print("Decorator 1")
func()
return wrapper
def decorator2(func):
def wrapper():
print("Decorator 2")
func()
return wrapper
@decorator1
@decorator2
def say_hello():
print("Hello!")
say_hello()
# 输出:
# Decorator 1
# Decorator 2
# Hello!
带状态的装饰器
有时候,我们希望装饰器能够记住一些状态信息。这可以通过使用类来实现。
class Counter:
def __init__(self, func):
self.func = func
self.count = 0
def __call__(self, *args, **kwargs):
self.count += 1
print(f"Function {self.func.__name__} has been called {self.count} times")
return self.func(*args, **kwargs)
@Counter
def say_hello():
print("Hello!")
say_hello() # 输出: Function say_hello has been called 1 times
say_hello() # 输出: Function say_hello has been called 2 times
实际应用
日志记录
import logging
def log_function_call(func):
def wrapper(*args, **kwargs):
logging.info(f"Calling {func.__name__} with args={args} kwargs={kwargs}")
result = func(*args, **kwargs)
logging.info(f"{func.__name__} returned {result}")
return result
return wrapper
@log_function_call
def add(a, b):
return a + b
add(3, 5)
缓存
from functools import lru_cache
@lru_cache(maxsize=128)
def fibonacci(n):
if n <= 1:
return n
return fibonacci(n - 1) + fibonacci(n - 2)
print(fibonacci(10)) # 输出: 55
总结
装饰器是 Python 中一个非常强大的工具,可以用来增强或修改函数和类的行为。通过理解和使用装饰器,你可以编写更加简洁、模块化和可维护的代码。