好吧,请原谅我,我知道这看起来很复杂,但请帮助我理解发生了什么。
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
“打包”到嵌套函数的本地作用域中吗?如果不是,对嵌套函数的调用如何查找局部变量?
我知道遇到这些问题通常意味着一个人“做错了”,但我想知道会发生什么。
我的理解是,当实际调用生成的pet_函数时,cage是在父函数名称空间中查找的,而不是以前。
所以当你这么做的时候
生成3个函数,找到最后创建的框架。
如果将最后一个循环替换为:
你会得到:
这源于以下原因
迭代后
i
的值被延迟存储为其最终值。作为生成器,该函数可以工作(即依次打印每个值),但是当转换为列表时,它在生成器上运行,因此对
cage
(cage.animal
)的所有调用都返回cats。嵌套函数在执行时从父作用域中查找变量,而不是在定义时。
编译函数体,验证“free”变量(不是通过赋值在函数本身中定义的),然后将其绑定为函数的闭包单元格,代码使用索引引用每个单元格。
pet_function
因此有一个自由变量(cage
),然后通过闭包单元索引0引用。闭包本身指向get_petters
函数中的局部变量cage
。当您实际调用函数时,该闭包将用于查看调用函数时周围作用域中
cage
的值。问题就在这里。当您调用函数时,get_petters
函数已经完成计算结果。在执行过程中的某个时刻,cage
局部变量被分配给每个'cow'
、'dog'
和'cat'
字符串,但是在函数的末尾,cage
包含最后一个值'cat'
。因此,当您调用每个动态返回的函数时,您将得到打印的值'cat'
。解决办法是不要依赖于闭包。您可以使用部分函数,创建新函数作用域,或者将变量绑定为关键字参数的默认值。
部分函数示例,使用^{} :
创建新范围示例:
将变量绑定为关键字参数的默认值:
不需要在循环中定义
scoped_cage
函数,编译只进行一次,而不是在循环的每次迭代中进行。相关问题 更多 >
编程相关推荐