如何在 Python 闭包中捕获值
How to capture a value in a Python Closure
如何在 python 闭包中捕获值(而不是引用)?
我尝试过的:
这是一个函数,它生成一个无参数函数列表,每个函数都吐出一个字符串:
def makeListOfFuncs( strings):
list = []
for str in strings:
def echo():
return str
list.append( echo)
return list
如果 python 中的闭包像所有其他语言一样工作,我希望这样的调用:
for animalFunc in makeListOfFuncs( ['bird', 'fish', 'zebra']):
print( animalFunc())
... 会产生这样的输出:
bird
fish
zebra
但是在 python 中,我们得到:
zebra
zebra
zebra
显然发生的事情是 echo
函数的闭包正在捕获对 str 的引用,而不是闭包构造时调用框架中的值。
如何定义 makeListOfFuncs,以便获得 'bird'、'fish'、'zebra'?
我找到了答案here on a blog post by Bob Kerner。
def makeListOfFuncs( strings):
list = []
for str in strings:
def generateFunc( str):
def echo():
return str
return echo
list.append( generateFunc( str))
return list
for animalFunc in makeListOfFuncs( ['bird', 'fish', 'zebra']):
print( animalFunc())
Python 闭包很奇怪。
Python 如果你知道闭包在 python.
中的内部工作原理,那么闭包并不奇怪
def makeListOfFuncs( strings):
list = []
for str in strings:
def echo():
return str
list.append( echo)
return list
您正在返回关闭列表。变量“str”在范围之间共享,它在两个不同的范围内。当 python 看到它时,它会创建一个中间对象。此对象包含对另一个对象“str”的引用。对于每个闭包,它都是同一个单元格。你可以测试一下:
closures_list= makeListOfFuncs( ['bird', 'fish', 'zebra'])
# Those will return same cell address
closures_list[0].__closure__
closures_list[1].__closure__
closures_list[2].__closure__
当您调用 makeListOfFuncs
时,它将 运行 for 循环,并且在循环结束时,中间对象将指向“zebra”。因此,当您调用每个闭包 print( animalFunc())
时,它将访问引用“zebra”的中间对象。
你必须考虑当 python 创建一个函数和计算它时会发生什么。
def echo():
return str
我们需要以某种方式捕获“str”的值作为正在创建的函数。因为如果你等到函数被评估,那就太晚了。另一种解决方案是定义默认值:
def makeListOfFuncs( strings):
list = []
for str in strings:
def echo(y=str):
return y
list.append( echo)
return list
for animalFunc in makeListOfFuncs( ['bird', 'fish', 'zebra']):
print( animalFunc())
此解决方案有效,因为默认值在创建时进行评估。所以当创建echo
时,将使用默认值“str”。默认值不会指向单元格。
在第一次迭代中,默认值为“bird”。 Python 不会将其视为 free variable
。在这种情况下,我们甚至没有创建闭包,我们正在创建函数。在下一次迭代中打印“fish”,在最后一次迭代中打印“zebra”
如何在 python 闭包中捕获值(而不是引用)?
我尝试过的:
这是一个函数,它生成一个无参数函数列表,每个函数都吐出一个字符串:
def makeListOfFuncs( strings):
list = []
for str in strings:
def echo():
return str
list.append( echo)
return list
如果 python 中的闭包像所有其他语言一样工作,我希望这样的调用:
for animalFunc in makeListOfFuncs( ['bird', 'fish', 'zebra']):
print( animalFunc())
... 会产生这样的输出:
bird
fish
zebra
但是在 python 中,我们得到:
zebra
zebra
zebra
显然发生的事情是 echo
函数的闭包正在捕获对 str 的引用,而不是闭包构造时调用框架中的值。
如何定义 makeListOfFuncs,以便获得 'bird'、'fish'、'zebra'?
我找到了答案here on a blog post by Bob Kerner。
def makeListOfFuncs( strings):
list = []
for str in strings:
def generateFunc( str):
def echo():
return str
return echo
list.append( generateFunc( str))
return list
for animalFunc in makeListOfFuncs( ['bird', 'fish', 'zebra']):
print( animalFunc())
Python 闭包很奇怪。
Python 如果你知道闭包在 python.
中的内部工作原理,那么闭包并不奇怪def makeListOfFuncs( strings):
list = []
for str in strings:
def echo():
return str
list.append( echo)
return list
您正在返回关闭列表。变量“str”在范围之间共享,它在两个不同的范围内。当 python 看到它时,它会创建一个中间对象。此对象包含对另一个对象“str”的引用。对于每个闭包,它都是同一个单元格。你可以测试一下:
closures_list= makeListOfFuncs( ['bird', 'fish', 'zebra'])
# Those will return same cell address
closures_list[0].__closure__
closures_list[1].__closure__
closures_list[2].__closure__
当您调用 makeListOfFuncs
时,它将 运行 for 循环,并且在循环结束时,中间对象将指向“zebra”。因此,当您调用每个闭包 print( animalFunc())
时,它将访问引用“zebra”的中间对象。
你必须考虑当 python 创建一个函数和计算它时会发生什么。
def echo():
return str
我们需要以某种方式捕获“str”的值作为正在创建的函数。因为如果你等到函数被评估,那就太晚了。另一种解决方案是定义默认值:
def makeListOfFuncs( strings):
list = []
for str in strings:
def echo(y=str):
return y
list.append( echo)
return list
for animalFunc in makeListOfFuncs( ['bird', 'fish', 'zebra']):
print( animalFunc())
此解决方案有效,因为默认值在创建时进行评估。所以当创建echo
时,将使用默认值“str”。默认值不会指向单元格。
在第一次迭代中,默认值为“bird”。 Python 不会将其视为 free variable
。在这种情况下,我们甚至没有创建闭包,我们正在创建函数。在下一次迭代中打印“fish”,在最后一次迭代中打印“zebra”