订单可变参考和分配的嵌套函数

问题描述:

Google Style Guide上词法作用域:订单可变参考和分配的嵌套函数

嵌套Python函数可以指在包围 函数定义的变量,但是不能分配给他们。

此规范可以在这里看到:

def toplevel(): 
    a = 5 
    def nested(): 
     # Tries to print local variable `a`, but `a` is created locally after, 
     # so `a` is referenced before assignment. You would need `nonlocal a` 
     print(a + 2) 
     a = 7 
    nested() 
    return a 
toplevel() 
# UnboundLocalError: local variable 'a' referenced before assignment 

扭转nested两个语句的顺序摆脱这个问题:

def toplevel(): 
    a = 5 
    def nested(): 
     # Two statements' order reversed, `a` is now locally assigned and can 
     # be referenced 
     a = 7 
     print(a + 2) 
    nested() 
    return a 
toplevel() 

我的问题是,是什么关于Python的实现,告诉第一个函数a将在本地声明(在print语句之后)?我的理解是,Python是逐行有效地解释的。那么,它不应该默认在代码中寻找非本地a

具体地说就是,如果我是使用只是参考(不分配),

def toplevel(): 
    a = 5 
    def nested(): 
     print(a + 2) 
    nested() 
    return a 
toplevel() 

莫名其妙print语句知道要引用封闭函数定义的非本地a。但如果我在之后分配给当地的a,那么该功能对于自己的功能来说就太聪明了。

我的理解是,Python被逐行有效地解释。

这不是正确的心智模式。

分析整个函数的主体以确定哪些名称引用局部变量,哪些不引用。

为了简化你的榜样,下面还给出了UnboundLocalError

def func(): 
    print(a) 
    a = 2 

func() 

这里,func()编译下面的字节码:

2   0 LOAD_FAST    0 (a) 
       3 PRINT_ITEM 
       4 PRINT_NEWLINE 

    3   5 LOAD_CONST    1 (2) 
       8 STORE_FAST    0 (a) 
      11 LOAD_CONST    0 (None) 
      14 RETURN_VALUE 

def gunc(): 
    print(a) 

其编译比较一下到

2   0 LOAD_GLOBAL    0 (a) 
       3 PRINT_ITEM 
       4 PRINT_NEWLINE 
       5 LOAD_CONST    0 (None) 
       8 RETURN_VALUE 

观察a的赋值缺席情况是如何将参考文献从局部变为全局的。

我的理解是,Python是有效地线

这就是你错了解释线。在任何解释开始之前,整个文件被编译为字节码。

此外,即使字节码编译通道不存在,print(a + 2)也不会在看到a = 7之前执行,因为它在函数定义中。到它实际尝试执行时,Python仍然知道a = 7print(a + 2)

+0

也许OP意思是字节码是按指令执行的,这是正确的。不是吗? – direprobs

+0

@direprobs:它不像你想象的那么正确,因为函数调用(明确的或者隐含在'+'之类的东西中)通常会导致字节码指令在其他字节码指令的中间执行,但无论如何,我认为提问者确实意味着逐行。 – user2357112

document

的Python的一个特别之处就是 - 如果没有global声明生效 - 分配到的名字总是进入最里面的范围。分配不会复制数据 - 它们只是将名称绑定到对象。