005-装饰器.py

一、装饰器是什么?

装饰器是一个 高阶函数,它接受一个函数作为输入,返回一个新的函数(或修改后的函数)。
核心作用:在不修改原函数代码的前提下,动态增强函数的功能(如日志、计时、权限校验等)。

二、装饰器基础原理

1. 函数是“一等公民”

Python 中函数可以作为变量传递、赋值或返回:

1
2
3
4
5
6
def say_hello():
print("Hello!")

# 将函数赋值给变量
func = say_hello
func() # 输出 "Hello!"

2. 闭包(Closure)

闭包是嵌套函数中,内部函数捕获了外部函数的变量:

1
2
3
4
5
6
7
8
def outer(msg):
def inner():
print(msg) # inner捕获了外部函数的msg变量
return inner


closure = outer("Hello, Closure!")
closure() # 输出 "Hello, Closure!"

三、实现一个简单装饰器

示例1:记录函数执行时间

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import time
def timer_decorator(func):
def wrapper():
start_time = time.time()
func()
end_time = time.time()
print(f"函数 {func.__name__} 执行耗时: {end_time - start_time:.4f}秒")
return wrapper


def my_function():
time.sleep(2)
print("函数执行完毕")

print("-----")
variation_func = timer_decorator(my_function)
variation_func()

@timer_decorator # 语法糖: 等价于 my_function = timer_decorator(my_function)
def my_decorated_function():
time.sleep(2)
print("函数执行完毕")


print("-------")
my_decorated_function()

四、处理带参数的函数

使用 *args**kwargs 接收任意参数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
def args_decorator(func):
def inner(*args, **kwargs):
"""
Closure Code
:param *args: This allows the function to receive any number of positional arguments. It collects them into a tuple.
:param **kwargs: This allows the function to receive any number of keyword arguments. It collects them into a dictionary.
:return: result
"""
print("decorator---begin")
result = func(*args, **kwargs) # 传递所有参数到原函数
print("decorator---end")
return result

return inner


@args_decorator
def add(a, b):
return a + b

"""
没有添加装饰器的写法
variation_func = args_decorator(add)
result = variation_func(3, 4)
print(result) # 输出 7
"""
print(add(3, 4)) # 输出 7

五、保留原函数元信息

使用 functools.wraps 保留原函数的名称、文档等元信息:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from functools import wraps
def lx_decorator(func):
@wraps(func) # 保留原函数元信息 This is important for debugging and introspection purposes, as it ensures that the decorated function retains the same identity as the original function.
def wrapper(*args, **kwargs):
print("decorator logic")
return func(*args, **kwargs)
return wrapper

@lx_decorator
def example_func():
"""This is an example function."""
pass

print(example_func.__name__)
print(example_func.__doc__)

六、带参数的装饰器

装饰器本身接受参数,需要三层嵌套函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
def repeat(n):
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
for _ in range(n):
result = func(*args, **kwargs)
return result
return wrapper
return decorator

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

greet("重要的事情说三遍")

七、类装饰器

通过实现 __call__ 方法让类成为装饰器:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Logger:
def __init__(self, func):
self.func = func

def __call__(self, *args, **kwargs):
print(f"函数 {self.func.__name__} 开始执行")
result = self.func(*args, **kwargs)
print(f"函数 {self.func.__name__} 执行完毕")
return result


@Logger
def say_hi(name):
print(f"Hi, {name}!")

say_hi("Lenthiu")

八、实际应用场景

  1. 权限验证:检查用户是否登录。
  2. 日志记录:记录函数调用信息。
  3. 性能监控:统计函数执行时间。
  4. 缓存加速:缓存函数计算结果(如 functools.lru_cache)。
  5. 错误重试:自动重试失败的操作。

九、总结

  • 核心思想:通过高阶函数和闭包,动态扩展函数功能。
  • 优势:代码复用、逻辑解耦、增强灵活性。
  • 注意点
    • 使用 @wraps 保留元信息。
    • 嵌套过多会降低可读性(避免过度使用)。

005-装饰器.py
https://jackiedai.github.io/2025/03/11/011Python/007Python-装饰器/
Author
lingXiao
Posted on
March 11, 2025
Licensed under