在Python中编写(而不是)全局变量

DCS*_*DCS 6 python global-variables python-2.7 python-internals

来自动态较少的C++,我在理解这个Python(2.7)代码的行为时遇到了一些麻烦.

注意:我知道这是糟糕的编程风格/邪恶,但我想了解它.

vals = [1,2,3]

def f():
    vals[0] = 5
    print 'inside', vals

print 'outside', vals
f()
print 'outside', vals
Run Code Online (Sandbox Code Playgroud)

此代码运行时没有错误,并f操纵(看似)全局列表.这与我之前的理解相反,即必须将函数中要操作(而不仅仅是读取)的全局变量声明为global ....

另一方面,如果我替换vals[0] = 5vals += [5,6],UnboundLocalError除非我添加一个global vals,否则执行失败f.这也是我在第一种情况下预期会发生的事情.

你能解释一下这种行为吗?

为什么我可以vals在第一种情况下操纵?为什么第二种操作失败而第一种操作失败?

更新: 在评论中评论说vals.extend(...)没有global.这增加了我的困惑 - 为什么+=与来电不同extend

Vol*_*ity 6

global仅在尝试更改变量引用的对象时才需要.因为vals[0] = 5更改实际对象而不是引用,所以不会引发错误.但是,使用时vals += [5, 6],解释器会尝试查找局部变量,因为它无法更改全局变量.

令人困惑的是,使用+=带有列表的运算符会修改原始列表,例如vals[0] = 5.而vals += [5, 6]失败,vals.extend([5, 6])工作.我们可以寻求帮助,dis.dis借给我们一些线索.

>>> def a(): v[0] = 1
>>> def b(): v += [1]
>>> def c(): v.extend([1])
>>> import dis
>>> dis.dis(a)
  1           0 LOAD_CONST               1 (1)
              3 LOAD_GLOBAL              0 (v)
              6 LOAD_CONST               2 (0)
              9 STORE_SUBSCR        
             10 LOAD_CONST               0 (None)
             13 RETURN_VALUE        
>>> dis.dis(b)
  1           0 LOAD_FAST                0 (v)
              3 LOAD_CONST               1 (1)
              6 BUILD_LIST               1
              9 INPLACE_ADD         
             10 STORE_FAST               0 (v)
             13 LOAD_CONST               0 (None)
             16 RETURN_VALUE        
d
>>> dis.dis(c)
  1           0 LOAD_GLOBAL              0 (v)
              3 LOAD_ATTR                1 (extend)
              6 LOAD_CONST               1 (1)
              9 BUILD_LIST               1
             12 CALL_FUNCTION            1
             15 POP_TOP             
             16 LOAD_CONST               0 (None)
             19 RETURN_VALUE
Run Code Online (Sandbox Code Playgroud)

我们可以看到函数ac使用LOAD_GLOBAL,而b试图使用LOAD_FAST.我们现在可以看到为什么使用+=不起作用 - 解释器尝试加载v为局部变量,因为它具有就地添加的默认行为.因为它不知道是否v是列表,所以它基本上假定该行的含义相同v = v + [1].