本文介绍了在Python中写入(而非写入)全局变量的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Coming from much less dynamic C++, I have some trouble understanding the behaviour of this Python (2.7) code.

注意:我知道这是不好的编程风格/邪恶,但我希望对此有所了解.

Note: I am aware that this is bad programming style / evil, but I would like to understand it non the less.

vals = [1,2,3]

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

print 'outside', vals
f()
print 'outside', vals

此代码运行无错误,并且f操作(看似)全局列表.这与我先前的理解相反,必须将要在函数中操作(且不仅要读取)的全局变量声明为global ....

This code runs without error, and f manipulates the (seemingly) global list. This is contrary to my prior understanding that global variables that are to be manipulated (and not only read) in a function must be declared as global ....

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

On the other hand, if I replace vals[0] = 5 with vals += [5,6], execution fails with an UnboundLocalError unless I add a global vals to f. This is what I would have expected to happen in the first case as well.

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

Could you explain this behaviour?

为什么在第一种情况下可以操纵vals?为什么第二种类型的操作会失败而第一种类型的却不会失败?

Why can I manipulate vals in the first case? Why does the second type of manipulation fail while the first does not?

更新:注释中指出,vals.extend(...)在不使用global的情况下可以工作.这加剧了我的困惑-为什么+=的处理方式不同于对extend的调用?

Update:It was remarked in a comment that vals.extend(...) works without global. This adds to my confusion - why is += treated differently from a call to extend?

推荐答案

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

global is only needed when you are trying to change the object which the variable references. Because vals[0] = 5 changes the actual object rather than the reference, no error is raised. However, with vals += [5, 6], the interpreter tries to find a local variable because it can't change the global variable.

令人困惑的是,将+=运算符与list一起使用会修改原始列表,例如vals[0] = 5.而vals += [5, 6]失败,而vals.extend([5, 6])起作用.我们可以争取 dis.dis 的帮助,为我们提供一些帮助线索.

The confusing thing is that using the += operator with list modifies the original list, like vals[0] = 5. And whereas vals += [5, 6] fails, vals.extend([5, 6]) works. We can enlist the help of dis.dis to lend us some clues.

>>> 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

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

We can see that functions a and c use LOAD_GLOBAL, whereas b tries to use LOAD_FAST. We can see now why using += won't work - the interpreter tries to load v as a local variable because of it's default behaviour with in-place addition. Because it can't know whether v is a list or not, it essentially assumes that the line means the same as v = v + [1].

这篇关于在Python中写入(而非写入)全局变量的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-13 01:23