装饰器(decorator)能在不改变原函数代码的前提下,给它增加额外功能,比如计时、日志、权限校验。它是 Python 优雅设计的典范。

一、本质:函数也是对象

Python 里函数是一等对象,可以赋值给变量、作为参数传递、作为返回值。装饰器正是利用这一点。

二、手写一个计时装饰器

import time

def timer(func):
    def wrapper(*args, **kwargs):
        start = time.time()
        result = func(*args, **kwargs)
        print(f"{func.__name__} 耗时 {time.time()-start:.3f}s")
        return result
    return wrapper

@timer
def my_func():
    time.sleep(1)
    print("执行完毕")

@timer 等价于 my_func = timer(my_func)

三、带参数的装饰器

需要三层嵌套来接收参数:

def repeat(n):
    def decorator(func):
        def wrapper(*args, **kwargs):
            for _ in range(n):
                func(*args, **kwargs)
        return wrapper
    return decorator

@repeat(3)        # 重复执行 3 次
def greet():
    print("hi")

四、用 functools.wraps 保留原信息

装饰后,函数的 __name__ 等元信息会变成 wrapper 的。用 @wraps 修复:

from functools import wraps

def timer(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        ...
    return wrapper
实战中装饰器常用于:日志记录、性能监控、权限校验、缓存(@lru_cache)、重试机制等。是 DRY 原则的利器。

五、类装饰器

除了函数,类也可以作为装饰器,__call__ 方法定义调用行为:

class Counter:
    def __init__(self, func):
        self.func = func
        self.count = 0
    def __call__(self, *args):
        self.count += 1
        return self.func(*args)

六、小结

装饰器初学可能绕,但理解"函数是对象、装饰器接收函数返回函数"后,就豁然开朗。掌握它能写出更优雅、更复用的代码。