Python中的Local,Global和对象

时间:2012-08-28 02:11:13

标签: python

我对Python中的局部和全局变量以及全局对象有疑问。看看这段代码:

var = 0

class Test():
    var = 0

test = Test()

def sum():
    Test.var += 1
    test.var += 1
    var += 1

sum()

如果我运行该代码,则仅在“var + = 1”行中触发异常。前两行有效。我从Python FAQ中读到了this question。我认为函数的前两行没有异常,因为引用了“Test”和“test”。成员“var”已分配,但“Test”和“test”是全局的,因为引用它来获取成员。 FAQ说:“在Python中,仅在函数内引用的变量是隐式全局的。如果在函数体内的任何位置为变量赋值,则假定它是本地的。”

所以,问题是......我的假设是真的吗?

3 个答案:

答案 0 :(得分:2)

看看这些功能:

def f():
    var += 1

def g():
    var = var.__iadd__(1)

gf函数的文字版本(当然Python在第一个版本中使用INPLACE_ADD操作码而不查找__iadd__属性)。

但是,正如您所看到的,名称var被加载一次并在这两个函数中存储一次。因此,如果你分配一个变量,就像FAQ所说的那样,它是本地变量,除非你先将它声明为全局变量。

那么,如何加载一个尚不存在的局部变量来汇总1,然后再次存储同名?

类属性有效,因为您正在执行:

Test.var = Test.var.__iadd__(1)

var确实存在于Test范围内(因此可以查找并重新分配)。

答案 1 :(得分:1)

  

我认为前两行中没有例外   函数,因为引用了“测试”和“测试”。

正确。它们引用了类属性var,而不是您定义的全局属性。

  

分配成员“var”,但“Test”和“test”是全局的,因为引用它来获取成员。

或者换句话说,Testtest在全局命名空间中可用,因此Test.vartest.var可以正常工作。

如果在var中未更改sum()的值,则会得到0,因为它上面的行已经更改了Test类属性而不是全局属性。总计添加一些print并删除var += 1

def sum():
    Test.var += 1
    print Test.var
    test.var += 1
    print test.var
    print var

sum()

...给出:

1
2
0

但是当我尝试在sum函数中为var赋值时,我甚至在该行之前得到一个错误:

>>> def sum():
...     Test.var += 1
...     print Test.var
...     test.var += 1
...     print test.var
...     print var
...     var += 1
...     print var
... 
>>> sum()
1
2
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 6, in sum
UnboundLocalError: local variable 'var' referenced before assignment

因为var现在被赋予sum()中的值,所以它被认为是本地的,但在该行之前尚未定义。 (这意味着python正在做一些“向前看”或在sum()中检查variable scope,因为它在print var被重新绑定之前引发了第一个var的错误。放置{{ 1}}而不是var = 50引发相同的错误。)

使用全局变量:

var += 1

输出:

def sum():
    Test.var += 1
    print Test.var
    test.var += 1
    print test.var
    global var #added the global keyword
    print var
    var += 1
    print var

编辑:关于我提到的“向前看”行为。会发布一个关于它的问题,但在这个答案中已经解释得很好:https://stackoverflow.com/a/370380/1431750(到Python variable scope error

答案 2 :(得分:0)

本质上,规则是为了避免含糊不清:

var = 0 # a variable in the global namespace

class Test():
    var = 0 # this is a attribute of the Test class

test = Test()

def sum():
    Test.var += 1
    test.var += 1 # these explicity mention on which object the name 
                  # should be stored

    blah = var    # reads from a outer scope, but assigns to a local variable
    var = Test    # new local variable which shadows the outer name
                  # not great but understandable

    var += 1 # this looks like it assigns to a local variable
             # but since a name from a outer scope is read first,
             # Python is not sure what the programmer really want to do
             # (maybe assign to the outer scope, or first read it then shadow?)
             # instead of guessing Python raises an exception, 
             # forcing the programmer to use `global` or a different name