Python recognize/not 什么时候识别 main 中的变量?

When does Python recognize/not recognize variables from main?

函数何时(如果有的话)识别已在 main 函数中初始化的变量?

例如:当我写下面的Python代码时:

def plus():
    variable += 1

if __name__ == '__main__': 
    variable = 1
    plus()

我收到以下错误:UnboundLocalError: local variable 'variable' referenced before assignment

然而,当我做类似的事情时,但是 dictionary:

def plus():
    dic[1] += 1

if __name__ == '__main__':
    dic = {}
    dic[1] = 1
    plus()
    print dic[1]

输出为:2

这两种情况有什么区别?

+= 运算符在与 simple 变量一起使用时被视为赋值。因此,Python 在解析函数体时将在 <function_object>.func_code.co_varnames 中添加 variable,因此在运行时 Python 将永远不会在任何其他范围内查找该变量,除非你有函数顶部的 globalnonlocal 声明(仅限 Python 3)。请注意,在使用 += 之前使用 variable 并不重要(请参阅最后一个示例),该变量现在在函数体的任何地方都是局部的。

>>> def plus():
...     var += 1
...     
>>> dis.dis(plus)
  2           0 LOAD_FAST                0 (var)
              3 LOAD_CONST               1 (1)
              6 INPLACE_ADD         
              7 STORE_FAST               0 (var)
             10 LOAD_CONST               0 (None)
             13 RETURN_VALUE   

另一方面,dic[1] 是变量查找,后跟 BINARY_SUBSCR(same thing for LOAD_ATTR as well; you can do x.extend([100]) but not x+=[100]; where x is a list) and as there are no assignment statements related to dic after that Python considers it as a either a global variable(LOAD_GLOBAL) or a free variable(LOAD_DEREF) 并从那里获取它的值。

>>> def plus():
    var[0] += 1
...     
>>> dis.dis(plus)
  2           0 LOAD_GLOBAL              0 (var)
              3 LOAD_CONST               1 (0)
              6 DUP_TOPX                 2
              9 BINARY_SUBSCR       
             10 LOAD_CONST               2 (1)
             13 INPLACE_ADD         
             14 ROT_THREE           
             15 STORE_SUBSCR        
             16 LOAD_CONST               0 (None)
             19 RETURN_VALUE        

>>> def plus_with_twist():
    var[0] += 1  # this will fail due to the next line
    var += 1     # Now `var` is a local variable everywhere in the function body
>>> dis.dis(plus_with_twist)
  2           0 LOAD_FAST                0 (var)
              3 LOAD_CONST               1 (0)
              6 DUP_TOPX                 2
              9 BINARY_SUBSCR       
             10 LOAD_CONST               2 (1)
             13 INPLACE_ADD         
             14 ROT_THREE           
             15 STORE_SUBSCR        

  3          16 LOAD_FAST                0 (var)
             19 LOAD_CONST               2 (1)
             22 INPLACE_ADD         
             23 STORE_FAST               0 (var)
             26 LOAD_CONST               0 (None)
             29 RETURN_VALUE