好的,请耐心等待,我知道这看起来会非常令人费解,但请帮助我了解正在发生的事情。
from functools import partial
class Cage(object):
def __init__(self, animal):
self.animal = animal
def gotimes(do_the_petting):
do_the_petting()
def get_petters():
for animal in ['cow', 'dog', 'cat']:
cage = Cage(animal)
def pet_function():
print "Mary pets the " + cage.animal + "."
yield (animal, partial(gotimes, pet_function))
funs = list(get_petters())
for name, f in funs:
print name + ":",
f()
给予:
cow: Mary pets the cat.
dog: Mary pets the cat.
cat: Mary pets the cat.
所以基本上,为什么我没有得到三种不同的动物? cage
不是“打包”到嵌套函数的本地范围内吗?如果没有,调用嵌套函数如何查找局部变量?
我知道遇到这类问题通常意味着一个人“做错了”,但我想了解会发生什么。
最佳答案
嵌套函数在执行时从父作用域查找变量,而不是在定义时。
编译函数体,验证“自由”变量(未在函数本身中通过赋值定义),然后将其作为闭包单元绑定(bind)到函数,代码使用索引来引用每个单元。 pet_function
因此有 一个 自由变量(cage
),然后通过闭包单元引用,索引为 0。闭包本身指向局部变量get_petters
函数中的 cage
。
当您实际调用该函数时,该闭包将用于查看 调用该函数时 周围范围内的 cage
的值。问题就在这里。当你调用你的函数时,get_petters
函数已经完成了计算它的结果。 cage
局部变量在执行期间的某个时间点被分配了 'cow'
、'dog'
和 'cat 中的每一个'
字符串,但在函数末尾,cage
包含最后一个值 'cat'
。因此,当您调用每个动态返回的函数时,您会打印出 'cat'
值。
解决方法是不要依赖闭包。您可以改用部分函数,创建新函数范围,或将变量绑定(bind)为关键字参数的默认值。 p>
部分函数示例,使用
functools.partial()
:from functools import partial def pet_function(cage=None): print "Mary pets the " + cage.animal + "." yield (animal, partial(gotimes, partial(pet_function, cage=cage)))
创建一个新的作用域示例:
def scoped_cage(cage=None): def pet_function(): print "Mary pets the " + cage.animal + "." return pet_function yield (animal, partial(gotimes, scoped_cage(cage)))
将变量绑定(bind)为关键字参数的默认值:
def pet_function(cage=cage): print "Mary pets the " + cage.animal + "." yield (animal, partial(gotimes, pet_function))
循环中不需要定义scoped_cage
函数,编译只发生一次,而不是循环的每次迭代。
关于python - 嵌套函数中的局部变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12423614/