Python 进阶:装饰器
什么是装饰器
装饰器是 Python 的元编程特性,允许在不修改原函数的情况下增加功能:
python
# 装饰器本质是一个函数
# 输入一个函数,返回一个增强后的函数
def my_decorator(func):
def wrapper(*args, **kwargs):
print("函数开始执行")
result = func(*args, **kwargs)
print("函数执行结束")
return result
return wrapper
@my_decorator
def say_hello(name):
print(f"Hello, {name}!")
return f"Hello, {name}!"
# 等价于:
# say_hello = my_decorator(say_hello)
result = say_hello("Alice")
# 输出:
# 函数开始执行
# Hello, Alice!
# 函数执行结束1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
带参数的装饰器
python
def repeat(times):
"""装饰器工厂:返回一个装饰器"""
def decorator(func):
def wrapper(*args, **kwargs):
for _ in range(times):
result = func(*args, **kwargs)
return result
return wrapper
return decorator
@repeat(3)
def greet(name):
print(f"Hello, {name}!")
greet("Alice")
# 输出: Hello, Alice! 三次1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
使用 functools.wraps
python
import functools
def my_decorator(func):
@functools.wraps(func) # 保留原函数元信息
def wrapper(*args, **kwargs):
"""这是包装函数"""
print("开始")
return func(*args, **kwargs)
return wrapper
@my_decorator
def original():
"""这是原始函数"""
pass
print(original.__name__) # original(而非 wrapper)
print(original.__doc__) # 这是原始函数1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
常见应用场景
1. 计时器
python
import functools
import time
def timer(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
start = time.time()
result = func(*args, **kwargs)
elapsed = time.time() - start
print(f"{func.__name__} 执行耗时: {elapsed:.3f}s")
return result
return wrapper
@timer
def slow_function():
time.sleep(1)1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2. 参数验证
python
def validate_age(func):
@functools.wraps(func)
def wrapper(age):
if not isinstance(age, int) or age < 0 or age > 150:
raise ValueError("年龄不合法")
return func(age)
return wrapper
@validate_age
def set_age(age: int):
print(f"设置为: {age}")1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
3. 日志记录
python
def log(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
print(f"[LOG] 调用 {func.__name__}")
result = func(*args, **kwargs)
print(f"[LOG] {func.__name__} 返回: {result}")
return result
return wrapper
@log
def add(a, b):
return a + b1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
4. 缓存(记忆化)
python
import functools
def memoize(func):
cache = {}
@functools.wraps(func)
def wrapper(*args):
if args not in cache:
cache[args] = func(*args)
return cache[args]
return wrapper
@memoize
def fibonacci(n):
if n < 2:
return n
return fibonacci(n-1) + fibonacci(n-2)1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
类装饰器
python
class CountCalls:
def __init__(self, func):
functools.update_wrapper(self, func)
self.func = func
self.call_count = 0
def __call__(self, *args, **kwargs):
self.call_count += 1
print(f"{self.func.__name__} 被调用 {self.call_count} 次")
return self.func(*args, **kwargs)
@CountCalls
def say_hello():
print("Hello!")1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
[[返回 Python 首页|python/index]]