首页 / Python3 入门教程 / 装饰器

Python3 入门教程

装饰器

本教程共 70 篇 · 第 25 篇 · 更新于 2026-07-22 · 约 2 分钟阅读

PythonPython3 入门教程装饰器functools.wraps@语法糖装饰器工厂

25. 装饰器

本节目标:理解装饰器的原理,能写无参和带参装饰器,掌握 functools.wraps 的用法。

什么是装饰器

装饰器是「在不修改原函数代码的前提下,给它增加额外功能」的技术。

本质上,装饰器是一个接收函数作为参数、返回新函数的高阶函数

最简单的装饰器

def my_decorator(func):
    def wrapper():
        print("函数执行前")
        func()
        print("函数执行后")
    return wrapper

def say_hello():
    print("Hello!")

# 手动装饰
say_hello = my_decorator(say_hello)
say_hello()
# 函数执行前
# Hello!
# 函数执行后

@ 语法糖

Python 提供 @ 符号让装饰更优雅:

@my_decorator
def say_hello():
    print("Hello!")

say_hello()

@my_decorator 等价于 say_hello = my_decorator(say_hello)

处理有参数的函数

*args, **kwargs 让装饰器兼容任意参数:

def my_decorator(func):
    def wrapper(*args, **kwargs):
        print("函数执行前")
        result = func(*args, **kwargs)
        print("函数执行后")
        return result
    return wrapper

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

greet("Alice")

functools.wraps

上面的装饰器有个问题:被装饰后的函数,名字和文档字符串都变了:

>>> greet.__name__
'wrapper'
>>> greet.__doc__
None

functools.wraps 把原函数的元信息复制回来:

from functools import wraps

def my_decorator(func):
    @wraps(func)          # 加上这一行
    def wrapper(*args, **kwargs):
        print("函数执行前")
        return func(*args, **kwargs)
    return wrapper

@my_decorator
def greet(name):
    """向某人问好。"""
    print(f"Hello, {name}!")

>>> greet.__name__
'greet'
>>> greet.__doc__
'向某人问好。'
Warning

写装饰器时一定要加 @wraps。不然调试时函数名全变成 wrapper,找 bug 会找疯。

实用装饰器:计时

import time
from functools import wraps

def timer(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        start = time.time()
        result = func(*args, **kwargs)
        elapsed = time.time() - start
        print(f"{func.__name__} 耗时: {elapsed:.4f} 秒")
        return result
    return wrapper

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

slow_function()
# 执行完毕
# slow_function 耗时: 1.0012 秒

带参数的装饰器

如果装饰器本身需要参数,需要再套一层函数:

def repeat(num_times):
    def decorator(func):
        @wraps(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")
# Hello, Alice!
# Hello, Alice!
# Hello, Alice!

三层嵌套:

  1. repeat(num_times) 接收装饰器参数
  2. decorator(func) 接收被装饰的函数
  3. wrapper(*args, **kwargs) 执行实际逻辑
Tip

带参数的装饰器也叫「装饰器工厂」。记住这个三层结构,写的时候就不容易晕。

多个装饰器堆叠

一个函数可以被多个装饰器修饰,执行顺序是从下往上:

@decorator_a
@decorator_b
def func():
    pass

# 等价于
func = decorator_a(decorator_b(func))

类方法装饰器

Python 内置了两个常用装饰器:

class MyClass:
    @staticmethod
    def static_method():
        """不依赖实例和类,就是普通函数放在类里"""
        pass

    @classmethod
    def class_method(cls):
        """第一个参数是类本身"""
        pass

后面面向对象章节会详细讲。


来源:参考了 runoob「Python3 装饰器」、liaoxuefeng「函数式编程」等,改写后所得。