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!
三层嵌套:
repeat(num_times)接收装饰器参数decorator(func)接收被装饰的函数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「函数式编程」等,改写后所得。