Python 装饰器原理与实战
本文由一缘原创整理,系统梳理 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 深度问题!