何时检查非局部变量的存在?

发布于 2021-01-29 18:01:54

我正在学习Python,现在我正在讨论范围和非本地语句。在某个时候,我以为我想通了一切,但是后来非本地人来了,把一切都分解了。

示例1:

print( "let's begin" )
def a():
    def b():
        nonlocal x
        x = 20
    b()

a()

运行它自然会失败。
更有趣的是print()没有执行。为什么?。

我的理解是,封闭def a()不执行之前print()执行,并嵌套def b()时,才会执行a()被调用。我很迷惑…

好,让我们尝试示例2:

print( "let's begin" )
def a():
    if False: x = 10
    def b():
        nonlocal x
        x = 20
    b()

a()

Aaand …运行良好。哇!!它是如何解决的?x = 10功能a永远不会执行!

我的理解是,非本地语句是在运行时评估和执行的,它搜索封闭函数的调用上下文,并将本地名称绑定x到某些特定的“外部” x。如果x外部函数没有-
引发异常。同样,在运行时。

但是现在看来,这似乎是在语法分析时完成的,只需进行愚蠢的检查,“检查外部函数x = blah是否存在,如果这样的话-我们很好,”即使x = blah从未执行过…

谁能解释我何时以及如何处理非本地语句?

关注者
0
被浏览
50
1 个回答
  • 面试哥
    面试哥 2021-01-29
    为面试而生,有面试问题,就找面试哥。

    您可以从的范围中看到b有关自由变量(可用于绑定)的了解范围a,如下所示:

    import inspect
    
    print( "let's begin" )
    
    def a():
        if False:
            x = 10
    
        def b():
            print(inspect.currentframe().f_code.co_freevars)
            nonlocal x
            x = 20
    
        b()
    
    a()
    

    这使:

    let's begin
    ('x',)
    

    如果您注释掉该nonlocal行,并删除其中的if语句,x则会看到可供使用的自由变量bis ()

    因此,让我们看一下它生成的字节码指令,方法是将的定义a放入IPython中,然后使用dis.dis

    In [3]: import dis
    
    In [4]: dis.dis(a)
      5           0 LOAD_CLOSURE             0 (x)
                  2 BUILD_TUPLE              1
                  4 LOAD_CONST               1 (<code object b at 0x7efceaa256f0, file "<ipython-input-1-20ba94fb8214>", line 5>)
                  6 LOAD_CONST               2 ('a.<locals>.b')
                  8 MAKE_FUNCTION            8
                 10 STORE_FAST               0 (b)
    
     10          12 LOAD_FAST                0 (b)
                 14 CALL_FUNCTION            0
                 16 POP_TOP
                 18 LOAD_CONST               0 (None)
                 20 RETURN_VALUE
    

    因此,让我们看一下如何LOAD_CLOSURE处理ceval.c

    TARGET(LOAD_CLOSURE) {
        PyObject *cell = freevars[oparg];
        Py_INCREF(cell);
        PUSH(cell);
        DISPATCH();
    }
    

    因此,我们看到它必须xfreevars封闭的范围中查找。

    执行模型文档中提到这一点,其中说:

    nonlocal语句使对应的名称引用最近的封闭函数范围中的先前绑定的变量。如果给定名称在任何封闭函数范围中不存在,则 在编译时
    引发SyntaxError 。



知识点
面圈网VIP题库

面圈网VIP题库全新上线,海量真题题库资源。 90大类考试,超10万份考试真题开放下载啦

去下载看看