本文由一缘原创整理,系统梳理 Python 装饰器的原理、用法、实战与易错点,配合代码和输出,适合所有 Python 开发者。

Python 装饰器原理与实战

装饰器是 Python 高级语法的代表,能让你的代码更优雅、可复用、可扩展。


1. 装饰器的本质

  • 装饰器本质是“函数接收函数,返回新函数”。
  • Python 一切皆对象,函数也可以作为参数和返回值。
def my_decorator(func):
    def wrapper():
        print("before")
        func()
        print("after")
    return wrapper

def say_hello():
    print("hello")

say_hello = my_decorator(say_hello)
say_hello()

输出:

before
hello
after

2. @语法糖

  • Python 提供 @decorator 语法糖,等价于 func = decorator(func)
def my_decorator(func):
    def wrapper():
        print("before")
        func()
        print("after")
    return wrapper

@my_decorator
def say_hi():
    print("hi")

say_hi()

输出:

before
hi
after

3. 带参数的装饰器

  • 装饰器本身也可以接收参数,需要多包一层函数
def repeat(n):
    def decorator(func):
        def wrapper(*args, **kwargs):
            for _ in range(n):
                func(*args, **kwargs)
        return wrapper
    return decorator

@repeat(3)
def greet(name):
    print(f"Hello, {name}!")

greet("Tom")

输出:

Hello, Tom!
Hello, Tom!
Hello, Tom!

4. 保留原函数签名与元信息

  • functools.wraps 保留原函数名、文档等元信息
import functools

def log(func):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        print(f"call {func.__name__}")
        return func(*args, **kwargs)
    return wrapper

@log
def add(a, b):
    """加法函数"""
    return a + b

print(add(1, 2))
print(add.__name__)
print(add.__doc__)

输出:

call add
3
add
加法函数

5. 常见装饰器应用场景

5.1. 缓存(记忆化)

from functools import lru_cache

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

print(fib(10))

输出:

55

5.2. 权限校验

def require_admin(func):
    def wrapper(user, *args, **kwargs):
        if user != 'admin':
            print("权限不足")
            return
        return func(user, *args, **kwargs)
    return wrapper

@require_admin
def delete_db(user):
    print(f"{user} 删除了数据库")

delete_db('guest')
delete_db('admin')

输出:

权限不足
admin 删除了数据库

5.3. 计时/性能分析

import time

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

@timer
def slow_add(a, b):
    time.sleep(0.5)
    return a + b

print(slow_add(1, 2))

输出:

耗时: 0.5xxs
3

6. 多层装饰器执行顺序

  • 多个装饰器从下往上包裹,先执行最外层
def deco1(func):
    def wrapper(*args, **kwargs):
        print("deco1 before")
        result = func(*args, **kwargs)
        print("deco1 after")
        return result
    return wrapper

def deco2(func):
    def wrapper(*args, **kwargs):
        print("deco2 before")
        result = func(*args, **kwargs)
        print("deco2 after")
        return result
    return wrapper

@deco1
@deco2
def foo():
    print("foo body")

foo()

输出:

deco1 before
deco2 before
foo body
deco2 after
deco1 after

7. 装饰器的最佳实践

  • 用 functools.wraps 保留元信息
  • 用 *args, **kwargs 保证通用性
  • 装饰器应返回新函数,不要直接执行原函数
  • 善用标准库装饰器(如 lru_cache、@property、@staticmethod、@classmethod)

结语

装饰器是 Python 的灵魂,理解它能让你写出更优雅、可维护的代码。欢迎留言交流更多 Python 深度问题!