

【个人主页:玄同765】
大语言模型(LLM)开发工程师|中国传媒大学·数字媒体技术(智能交互与游戏设计) 深耕领域:大语言模型开发 / RAG知识库 / AI Agent落地 / 模型微调 技术栈:Python / LangChain/RAG(Dify+Redis+Milvus)| SQL/NumPy | FastAPI+Docker ️ 工程能力:专注模型工程化部署、知识库构建与优化,擅长全流程解决方案 专栏传送门:LLM大模型开发 项目实战指南、Python 从真零基础到纯文本 LLM 全栈实战、从零学 SQL + 大模型应用落地、大模型开发小白专属:从 0 入门 Linux&Shell 「让AI交互更智能,让技术落地更高效」 欢迎技术探讨/项目合作! 关注我,解锁大模型与智能交互的无限可能!
本文将带你彻底理解Python中闭包、装饰器和类装饰器的核心原理,并通过实战案例展示它们在真实项目中的应用。
闭包(Closure)是Python中一个强大的特性,指一个函数对象记住并访问其定义时的环境,即使该环境已经不再存在。
def outer(x):
def inner(y):
return x + y
return inner
add_5 = outer(5)
print(add_5(3)) # 输出 8关键点:
inner 函数引用了外部函数 outer 的变量 xouter 已经执行完毕,add_5 仍然记住 x=5Python使用作用域链实现闭包。当函数被调用时,Python会创建一个栈帧(stack frame),保存局部变量。闭包的特殊之处在于:
def counter():
count = 0
def increment():
nonlocal count
count += 1
return count
return increment
counter1 = counter()
print(counter1()) # 1
print(counter1()) # 2装饰器本质上是一个闭包,它接受一个函数作为参数,并返回一个新函数,在不修改原函数代码的前提下增强其功能。
def my_decorator(func):
def wrapper():
print("Before function call")
func()
print("After function call")
return wrapper
@my_decorator
def say_hello():
print("Hello!")
say_hello()执行结果:
Before function call
Hello!
After function call@my_decorator 是 say_hello = my_decorator(say_hello) 的语法糖,让代码更清晰。
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("Alice") # 会输出3次当需要在装饰器中维护状态时,类装饰器比函数装饰器更合适。
类装饰器需要实现__call__方法,使类的实例可以像函数一样被调用。
class Repeat:
def __init__(self, n):
self.n = n
def __call__(self, func):
def wrapper(*args, **kwargs):
for _ in range(self.n):
func(*args, **kwargs)
return wrapper
@Repeat(3)
def greet(name):
print(f"Hello, {name}!")
greet("Bob")特性 | 函数装饰器 | 类装饰器 |
|---|---|---|
状态维护 | 需要nonlocal | 直接使用实例属性 |
可读性 | 简洁 | 适合复杂逻辑 |
调试 | 简单 | 可能需要查看类方法 |
适用场景 | 简单功能增强 | 需要状态管理的复杂场景 |
import time
def timer(func):
def wrapper(*args, **kwargs):
start = time.time()
result = func(*args, **kwargs)
end = time.time()
print(f"{func.__name__} took {end - start:.4f} seconds")
return result
return wrapper
@timer
def slow_function():
time.sleep(1)
return "Done"
slow_function()
# 输出: slow_function took 1.0002 secondsclass Cache:
def __init__(self, max_size=100):
self.cache = {}
self.max_size = max_size
self.order = []
def __call__(self, func):
def wrapper(*args):
key = str(args)
if key in self.cache:
return self.cache[key]
result = func(*args)
self.cache[key] = result
self.order.append(key)
# 维护缓存大小
if len(self.cache) > self.max_size:
del_key = self.order.pop(0)
del self.cache[del_key]
return result
return wrapper
@Cache(max_size=5)
def fibonacci(n):
if n < 2:
return n
return fibonacci(n-1) + fibonacci(n-2)
print(fibonacci(10)) # 计算并缓存
print(fibonacci(10)) # 直接从缓存获取# 模拟Flask的route装饰器
def route(path):
def decorator(func):
# 注册路由
print(f"Registered route: {path} -> {func.__name__}")
return func
return decorator
@route('/home')
def home():
return "Welcome to home!"
@route('/about')
def about():
return "About us"functools.wraps问题:装饰器会改变原函数的__name__和__doc__,影响调试和文档生成。
解决方案:
from functools import wraps
def my_decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
print("Before")
result = func(*args, **kwargs)
print("After")
return result
return wrapper问题:类装饰器的__init__接收装饰器参数,__call__接收被装饰函数。
正确做法:
class Decorator:
def __init__(self, n=1): # 接收装饰器参数
self.n = n
def __call__(self, func): # 接收被装饰函数
def wrapper(*args, **kwargs):
for _ in range(self.n):
func(*args, **kwargs)
return wrapperfunctools.wraps:保持函数元信息概念 | 核心 | 适用场景 |
|---|---|---|
闭包 | 函数记住定义环境 | 状态保持、工厂函数 |
装饰器 | 闭包的函数化应用 | 功能增强、日志、性能监控 |
类装饰器 | 用类实现装饰器 | 需要状态管理的复杂场景 |
关键洞察:
记住:装饰器不是魔法,而是函数式编程思想在Python中的优雅实现。理解闭包是掌握装饰器的基础,而类装饰器则是处理复杂场景的利器。
装饰器类型 | 语法 | 适用场景 |
|---|---|---|
简单装饰器 | @decorator | 日志、计时、权限检查 |
带参数的装饰器 | @decorator(arg) | 需要配置的装饰器(如重试次数) |
类装饰器 | @ClassDecorator() | 需要维护状态的装饰器(缓存、计数器) |
多层装饰器 | @decorator1 @decorator2 | 组合功能(如日志+缓存) |