闭包与自由变量
在内部函数中捕获状态
闭包与自由变量 是 CoddyKit 上的免费 Python Academy 课时。 这是第 2 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Python Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Python Academy 课程共包含 4 节课。
嵌套函数
Python 允许您在一个函数内部定义另一个函数。每次 outer 函数运行时,都会重新创建 inner 函数。
def outer():
def inner():
return 'from inner'
return inner()
print(outer())inner 可以看到 outer 变量
inner 函数可以读取外层函数中定义的变量。这些变量称为自由变量,因为它们不是 inner 函数的局部变量。
def outer():
message = 'hello'
def inner():
return message
return inner()
print(outer())什么是闭包
当 inner 函数被返回后,即使外层作用域已经结束,它仍然记得来自外层作用域的自由变量,这种情况就称为闭包。
def make_greeter(name):
def greet():
return 'Hi ' + name
return greet
g = make_greeter('Ada')
print(g())捕获的状态会保留下来
outer 函数已经返回了,但闭包仍然持有 name。这个值会继续存在于返回的函数内部。
def make_greeter(name):
def greet():
return 'Hi ' + name
return greet
a = make_greeter('Ada')
b = make_greeter('Bob')
print(a())
print(b())乘法器工厂
闭包非常适合用作生成定制函数的工厂。这里返回的每个函数都会乘以一个捕获的因子。
def multiplier(factor):
def multiply(n):
return n * factor
return multiply
double = multiplier(2)
triple = multiplier(3)
print(double(10))
print(triple(10))每个闭包彼此独立
工厂的每次调用都会创建一个独立的闭包,并拥有各自捕获的值。它们互不影响。
def adder(amount):
def add(n):
return n + amount
return add
add5 = adder(5)
add100 = adder(100)
print(add5(1), add100(1))检查闭包捕获的值
捕获的名称会列在 __code__.co_freevars 中,而这些名称对应的值存储在 __closure__ 单元中。
def make(x):
def f():
return x
return f
fn = make(42)
print(fn.__code__.co_freevars)
print(fn.__closure__[0].cell_contents)闭包捕获变量而不是值
闭包捕获的是变量本身,因此它看到的是变量的最终值。当变量在闭包创建后发生变化时,这一点就很重要。
def build():
x = 1
def show():
return x
x = 99
return show
print(build()())循环中的延迟绑定陷阱
一个经典的易错点是:循环中创建的闭包共享同一个循环变量,因此它们捕获的都是该变量的最后一个值。
funcs = []
for i in range(3):
funcs.append(lambda: i)
print([f() for f in funcs])修复延迟绑定
使用默认参数绑定当前值,这样每个闭包就能在定义时捕获自己的副本。
funcs = []
for i in range(3):
funcs.append(lambda i=i: i)
print([f() for f in funcs])闭包作为轻量级对象
闭包将数据与行为组合在一起,就像一个小型对象;对于简单情况,它通常比完整的类更简洁。
def counter_start(start):
def value():
return start
return value
c = counter_start(10)
print(c())快速检查
Python 中的闭包是什么?
回顾:闭包与自由变量
要点:
- inner 函数可以读取外层作用域中的变量(自由变量)。
- 闭包是一个被返回且会记住这些变量的 inner 函数。
- 工厂的每次调用都会创建一个独立的闭包。
- 闭包捕获的是变量而不是值,这会导致循环中的延迟绑定陷阱——可以使用默认参数修复。
def power_of(exp):
return lambda base: base ** exp
square = power_of(2)
print(square(9))常见问题解答
「闭包与自由变量」课时是免费的吗?
是的 — 「闭包与自由变量」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Python Academy 课程的其余内容,请升级到 CoddyKit PRO。 Python Academy 课程共包含 4 节课。
「闭包与自由变量」这节课中我会学到什么?
在内部函数中捕获状态 你通过在浏览器中直接运行的动手代码来练习 Python Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 Python Academy 需要有经验吗?
无需任何先前经验。CoddyKit 上的 Python Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 2 节课,共 4 节。
「闭包与自由变量」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 Python Academy 课中编写并运行代码吗?
能。每节 Python Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。
此课程中的所有课时
- 一等函数
- 闭包与自由变量
- nonlocal 与可变状态
- 偏函数