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] = 5为vals += [5,6],UnboundLocalError除非我添加一个global vals,否则执行失败f.这也是我在第一种情况下预期会发生的事情.
你能解释一下这种行为吗?
为什么我可以vals在第一种情况下操纵?为什么第二种操作失败而第一种操作失败?
更新:
在评论中评论说vals.extend(...)没有global.这增加了我的困惑 - 为什么+=与来电不同extend?
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)
我们可以看到函数a和c使用LOAD_GLOBAL,而b试图使用LOAD_FAST.我们现在可以看到为什么使用+=不起作用 - 解释器尝试加载v为局部变量,因为它具有就地添加的默认行为.因为它不知道是否v是列表,所以它基本上假定该行的含义相同v = v + [1].
| 归档时间: |
|
| 查看次数: |
285 次 |
| 最近记录: |