是什么?
当一个函数内部定义了另一个函数,并且内部的函数引用了外部函数的变量,当外部函数返回内部函数时,就形成了一个闭包。
闭包的特点包括: 它可以访问其外部函数中定义的变量,即使外部函数已经执行完毕。这些变量会被“包裹”在闭包中,保持其状态。
作用?
保持变量状态
本质是利用变量作用域,实现内置,
记忆和缓存、私有方法和缓存
与 propery 实现的有啥区别
有哪些应用场景
缓存的实现,要求:唯一的入口,保持变量状态。闭包都可以实现
闭包与装饰器的关系?
闭包的变量查找规则 (LEGB):
闭包的变量作用域
# L - Local(最内层)
# E - Enclosing(闭包外层)
# G - Global(全局)
# B - Built-in(内置)
x = 10 # 全局变量
def outer():
x = 20 # 闭包外层变量
def inner():
# x = 30 # 如果有局部变量会优先使用
return x # 没有局部变量时,去外层找
return inner
f = outer()
print(f()) # 输出20,使用了闭包外层的值闭包的取值逻辑
闭包中的变量是动态查找的:
# 案例1:展示动态查找
x = 1
def make_func():
return lambda: x # 没有把x固定下来
f = make_func()
print(f()) # 输出1
x = 2
print(f()) # 输出2,因为每次调用都重新查找x- 默认参数是在函数定义时就求值:
# 案例2:展示默认参数的行为
x = 1
def make_func():
return lambda x=x: x # 把当前的x值固定为默认参数
f = make_func()
print(f()) # 输出1
x = 2
print(f()) # 还是输出1,因为x的值在创建lambda时就固定了这个行为在 Python 中很重要,特别是要注意:
- 循环中创建闭包的常见陷阱:
funcs = []
# 错误写法
for i in range(3):
funcs.append(lambda: i) # 所有函数都引用同一个i
print([f() for f in funcs]) # [2, 2, 2]
funcs = []
# 正确写法
for i in range(3):
funcs.append(lambda i=i: i) # 每个函数都有自己的i值
print([f() for f in funcs]) # [0, 1, 2]- 可变对象的特殊情况:
# 对可变对象要特别小心
data = []
f = lambda: data
data.append(1)
print(f()) # 输出[1],因为list是可变对象
# 如果要固定可变对象的状态
data = [1, 2]
f = lambda data=data.copy(): data # 创建副本作为默认参数
data.append(3)
print(f()) # 仍然输出[1, 2]