以下是 Python 中装饰器的高级用法总结,结合了多个实际应用场景和技术实现:


1. 带参数的装饰器

通过装饰器工厂模式动态生成装饰器,实现参数化功能扩展。例如,控制函数重复执行次数或添加条件判断逻辑。

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(3)  # 调用装饰器工厂生成装饰器
def greet(name):
    print(f"Hello, {name}!")

greet("Alice")  # 输出三次 "Hello, Alice!"

引用:[21] [26]


2. 类装饰器

使用类实现装饰器,通过 __init__ 和 __call__ 方法管理状态,支持更复杂的逻辑封装。

class Logger:
    def __init__(self, func):
        self.func = func

    def __call__(self, *args, **kwargs):
        print(f"Calling {self.func.__name__}")
        return self.func(*args, **kwargs)

@Logger
def add(a, b):
    return a + b

print(add(2, 3))  # 输出日志并返回5

引用:[3] [37]


3. 多层装饰器

多个装饰器叠加时,执行顺序由内到外(从下往上),需注意逻辑顺序对结果的影响。

def bold(func):
    def wrapper():
        return f"<b>{func()}</b>"
    return wrapper

def italic(func):
    def wrapper():
        return f"<i>{func()}</i>"
    return wrapper

@bold
@italic
def say_hi():
    return "Hi"

print(say_hi())  # 输出 "<b><i>Hi</i></b>"

引用:[13] [16]


4. 装饰器保留元数据

使用 functools.wraps 保留原函数的名称、文档等元信息,避免调试时信息丢失。

from functools import wraps

def log_decorator(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        print(f"{func.__name__} is called")
        return func(*args, **kwargs)
    return wrapper

@log_decorator
def example():
    """示例函数"""
    pass

print(example.__name__)  # 输出 "example"

引用:[4] [17]


5. 动态装饰器

运行时根据条件动态选择装饰行为,例如根据环境切换调试模式。

def debug_decorator(debug=True):
    def decorator(func):
        def wrapper(*args, **kwargs):
            if debug:
                print("Debug mode: logging inputs")
            return func(*args, **kwargs)
        return wrapper
    return decorator

@debug_decorator(debug=True)
def calculate(a, b):
    return a * b

calculate(3, 4)  # 输出调试信息

引用:[39]


6. 装饰器实现缓存

利用 functools.lru_cache 或自定义装饰器缓存函数结果,提升重复计算性能。

from functools import lru_cache

@lru_cache(maxsize=None)
def fibonacci(n):
    if n < 2:
        return n
    return fibonacci(n-1) + fibonacci(n-2)

print(fibonacci(10))  # 快速计算斐波那契数

引用:[4] [33]


7. 装饰器模式与面向切面编程(AOP)

通过装饰器分离核心逻辑与横切关注点(如日志、权限校验)。

def admin_required(func):
    def wrapper(user, *args, **kwargs):
        if not user.is_admin:
            raise PermissionError("Admin required")
        return func(user, *args, **kwargs)
    return wrapper

@admin_required
def delete_user(user):
    print(f"User {user.name} deleted")

# 调用时自动校验权限

引用:[34] [36]


8. 装饰器在框架中的应用

如 Flask 的路由装饰器、Django 的登录校验装饰器。

from flask import Flask
app = Flask(__name__)

@app.route("/")  # 路由装饰器
def home():
    return "Welcome!"

引用:[25]

9.在class类内使用装饰器

import logging
import functools

# 将装饰器移到类外,作为普通函数
def log_function_call(func):
    @functools.wraps(func)
    def wrapper(self, *args, **kwargs):
        self.logger.info(f'外部-a={self.a}')
        self.logger.info(f"Calling function {func.__name__} with args: {args}, kwargs: {kwargs}")
        try:
            result = func(self, *args, **kwargs)
            self.logger.info(f"Function {func.__name__} returned: {result}")
            self.logger.info(f'内部-a={self.a}')
            return result
        except Exception as e:
            self.logger.error(f"Function {func.__name__} raised an error: {e}")
            raise
    return wrapper

def two(self):
    print(f'two--{self.a}')

class do_decorator:
    def __init__(self):
        logging.basicConfig(level=logging.INFO)
        self.logger = logging.getLogger(__name__)
        self.a='a'

    @log_function_call  # 直接应用外部装饰器
    def api_endpoint(self, url):
        self.logger.info(f"Testing endpoint at {url}")

    def do_one(self):
        two(self)
        self.api_endpoint("https://example.com/api")

if __name__ == '__main__':
    one = do_decorator()
    one.do_one()

高级场景总结表

场景技术点引用来源
动态参数控制装饰器工厂模式[21]
类封装装饰逻辑类装饰器[3]
多层装饰器顺序装饰器堆叠执行顺序[13]
元数据保留functools.wraps[4]
动态切换行为条件化装饰器[39]
缓存优化lru_cache 或自定义[4]

注意事项

  • 避免过度装饰:嵌套过多装饰器可能降低代码可读性。
  • 调试工具支持:使用 inspect 模块检查装饰后的函数签名。
  • 性能影响:复杂装饰器可能引入额外开销,需权衡功能与性能。

如需进一步了解具体实现细节,可参考 [11] 中关于装饰器与设计模式的对比分析,或 [16] 中关于装饰器性能优化的讨论。

更多推荐