Python 闭包与装饰器 超详细精讲
一、前言:为什么要学闭包和装饰器?
闭包是函数高级用法,装饰器是Python 最优雅的语法糖。
学会它们,你能写出:
- 更简洁的代码
- 不修改原函数就能增加功能
- 日志、计时、权限、缓存等通用功能
- 符合企业级开发规范的代码
闭包是基础,装饰器是闭包的经典应用。
二、什么是闭包(Closure)?
1. 闭包定义(最通俗)
- 函数里面定义了内部函数
- 内部函数使用了外部函数的变量
- 外部函数返回内部函数名
满足这 3 点 = 闭包
2. 闭包三要素(必须背会)
- 外部函数嵌套内部函数
- 内部函数使用外部函数的变量
- 外部函数返回内部函数
3. 最简单闭包代码
# 外部函数
def outer(x):
# 外部函数变量
a = x
# 内部函数(闭包核心)
def inner():
# 使用外部函数变量
return a + 10
# 返回内部函数
return inner
# 创建闭包实例
func = outer(5)
# 调用内部函数
print(func()) # 15
4. 闭包特点
- 内部函数可以记住外部函数的环境
- 外部函数执行完毕,变量不会被销毁
- 可以实现数据隐藏和函数工厂
三、闭包经典案例:计数器
def counter():
count = 0 # 外部变量
def add():
nonlocal count # 声明修改外部变量
count += 1
return count
return add
# 创建计数器
c = counter()
print(c()) # 1
print(c()) # 2
print(c()) # 3
✅ 闭包让 count 变量一直保存在内存中
四、什么是装饰器(Decorator)?
1. 装饰器定义
- 在不修改原函数代码的前提下,给函数增加新功能
- 本质是闭包 + 语法糖 @
- 装饰器 = 闭包的实际应用
2. 装饰器作用
- 日志记录
- 执行时间统计
- 权限验证
- 缓存
- 参数检查
3. 装饰器语法
@装饰器名字
def 原函数():
pass
五、最简单装饰器(一步步写)
第1步:写装饰器(闭包)
# 装饰器函数
def my_decorator(func):
def wrapper():
print("函数执行前 —— 新增功能")
func() # 调用原函数
print("函数执行后 —— 新增功能")
return wrapper
第2步:写原函数
def say_hello():
print("Hello World")
第3步:使用装饰器
# 装饰
say_hello = my_decorator(say_hello)
# 调用
say_hello()
运行结果
函数执行前 —— 新增功能
Hello World
函数执行后 —— 新增功能
六、语法糖 @ 写法(最常用)
def my_decorator(func):
def wrapper():
print("函数执行前")
func()
print("函数执行后")
return wrapper
# 使用 @ 语法糖
@my_decorator
def say_hello():
print("Hello World")
say_hello()
✅ 效果一样,代码更优雅!
七、带参数的函数 + 装饰器
def my_decorator(func):
# wrapper 接收参数
def wrapper(a, b):
print("计算开始")
func(a, b)
print("计算结束")
return wrapper
@my_decorator
def add(a, b):
print(f"{a} + {b} = {a + b}")
add(10, 20)
运行结果
计算开始
10 + 20 = 30
计算结束
八、万能装饰器(适配所有函数)
使用 *args 和 **kwargs 适配任意参数、任意返回值
def decorator(func):
def wrapper(*args, **kwargs):
print("===== 功能开始 =====")
result = func(*args, **kwargs)
print("===== 功能结束 =====")
return result
return wrapper
@decorator
def add(a, b):
return a + b
print(add(1, 2))
九、装饰器经典案例:计时功能
计算函数执行时间(企业最常用)
import time
# 计时装饰器
def timer(func):
def wrapper(*args, **kwargs):
start = time.time()
res = func(*args, **kwargs)
end = time.time()
print(f"函数执行耗时:{end - start:.4f} 秒")
return res
return wrapper
@timer
def test():
time.sleep(1)
test()
十、装饰器经典案例:日志功能
def log(func):
def wrapper(*args, **kwargs):
print(f"调用函数:{func.__name__}")
print(f"参数:{args} {kwargs}")
return func(*args, **kwargs)
return wrapper
@log
def add(a, b):
return a + b
add(10, 20)
十一、多个装饰器叠加
def decorator1(func):
def wrapper():
print("装饰器1 —— 前")
func()
print("装饰器1 —— 后")
return wrapper
def decorator2(func):
def wrapper():
print("装饰器2 —— 前")
func()
print("装饰器2 —— 后")
return wrapper
# 执行顺序:从上到下装饰,从内到外执行
@decorator1
@decorator2
def func():
print("我是原函数")
func()
十二、带参数的装饰器(高级)
def log_level(level):
def decorator(func):
def wrapper(*args, **kwargs):
print(f"[{level}] 执行函数")
return func(*args, **kwargs)
return wrapper
return decorator
@log_level("INFO")
def test():
print("Hello")
test()
十三、闭包 vs 装饰器(总结表)
| 名称 | 关系 | 作用 | 形式 |
|---|---|---|---|
| 闭包 | 基础 | 保存数据、嵌套函数 | 外函数返内函数 |
| 装饰器 | 闭包应用 | 增强函数功能 | @xxx |
十四、 重点总结
- 闭包 = 嵌套函数 + 使用外部变量 + 返回内部函数
- 闭包可以记住外部环境,延长变量生命周期
- 装饰器 = 闭包 + 语法糖 @
- 装饰器不修改原函数,就能增加功能
- 万能装饰器使用
*args, **kwargs - 常用场景:计时、日志、权限、缓存

浙公网安备 33010602011771号