python - 嵌套函数中的局部变量

标签 python scope closures nested-function

好的,请耐心等待,我知道这看起来会非常令人费解,但请帮助我了解正在发生的事情。

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/

相关文章:

监视文件夹和更新数据库的 Python 守护进程

python - 如何在两个一起工作的脚本完成后自动启动脚本?

python - 将第一个出现的列添加到 groupby 数据框中

javascript - 停止 jQuery 函数在页面加载时运行

Jquery,从函数访问变量

python - 如何使用 rotozoom 在 pygame 中设置缩放和旋转动画

c++ - 从 `if constexpr` 分支扩展对象生命周期/范围

c++ - 使用 unique_ptr 离开范围时堆损坏

javascript - 检查变量是否设置在全局范围内?

ios - 在同步调用中执行异步任务