输入关键词开始搜索

Python 装饰器

函数是一等公民

def hello():
    return "Hello!"

# 函数可以赋值给变量
greet = hello
print(greet())          # Hello!

# 函数可以作为参数
def call_twice(fn):
    fn()
    fn()

# 函数可以定义在函数内部
def outer():
    def inner():
        return "inner"
    return inner()      # 返回 inner 的调用结果

闭包 → 装饰器

# 闭包 = 函数 + 捕获的外部变量
def make_multiplier(factor):
    def multiply(x):
        return x * factor   # factor 被"捕获"
    return multiply          # 返回内部函数

double = make_multiplier(2)
print(double(5))             # 10

装饰器就是语法糖:

# 下面两段等价:
@decorator
def foo(): ...

def foo(): ...
foo = decorator(foo)

基础装饰器

import time
from functools import wraps

def timer(func):
    @wraps(func)             # 保留原函数的 __name__ 和 __doc__
    def wrapper(*args, **kwargs):
        start = time.time()
        result = func(*args, **kwargs)
        elapsed = time.time() - start
        print(f"{func.__name__} took {elapsed:.4f}s")
        return result
    return wrapper

@timer
def slow_function():
    time.sleep(0.5)
    return "done"

slow_function()
# 输出: slow_function took 0.5001s

@wraps 不可省略 — 不加的话 slow_function.__name__ 会变成 "wrapper"

带参数的装饰器

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

@repeat(3)
def say_hello():
    print("Hello!")

say_hello()  # 打印 3 次
# 等价于: say_hello = repeat(3)(say_hello)

实战场景

场景 1:缓存(memoize)

def memoize(func):
    cache = {}
    @wraps(func)
    def wrapper(*args):
        if args not in cache:
            cache[args] = func(*args)
        return cache[args]
    return wrapper

@memoize
def fib(n):
    if n < 2: return n
    return fib(n-1) + fib(n-2)

print(fib(100))  # 毫秒级

场景 2:权限检查

def require_auth(role):
    def decorator(func):
        @wraps(func)
        def wrapper(user, *args, **kwargs):
            if user.get("role") != role:
                raise PermissionError(f"Need {role}")
            return func(user, *args, **kwargs)
        return wrapper
    return decorator

@require_auth("admin")
def delete_user(admin, target_id):
    print(f"Deleted {target_id}")

场景 3:重试

def retry(max_attempts=3, delay=1):
    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            for attempt in range(max_attempts):
                try:
                    return func(*args, **kwargs)
                except Exception as e:
                    if attempt == max_attempts - 1:
                        raise
                    print(f"Retry {attempt+1}/{max_attempts}: {e}")
                    time.sleep(delay)
        return wrapper
    return decorator

@retry(max_attempts=3, delay=2)
def unstable_api_call():
    ...

场景 4:日志

def log_calls(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        print(f"CALL {func.__name__}({args}, {kwargs})")
        result = func(*args, **kwargs)
        print(f"RETURN {func.__name__}{result!r}")
        return result
    return wrapper

类装饰器

class Singleton:
    def __init__(self, cls):
        self.cls = cls
        self.instance = None

    def __call__(self, *args, **kwargs):
        if self.instance is None:
            self.instance = self.cls(*args, **kwargs)
        return self.instance

@Singleton
class Database:
    def __init__(self):
        print("Init DB")

db1 = Database()   # Init DB (只打印一次)
db2 = Database()   # 返回同一个实例
print(db1 is db2)  # True