0

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

var = 0

class Test():
    var = 0

test = Test()

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

sum()

如果我运行该代码,则仅在“var += 1”行中触发异常。前两行有效。我从 Python FAQ 中读到了这个问题。我认为函数的前两行也不例外,因为引用了“Test”和“test”。分配了成员“var”,但“Test”和“test”是全局的,因为被引用以获取成员。常见问题解答说:“在 Python 中,仅在函数内部引用的变量是隐式全局的。如果一个变量在函数体中的任何位置被分配了一个新值,它就被假定为一个局部变量。”

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

4

3 回答 3

2

看看这些函数:

def f():
    var += 1

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

gf函数所做的文字版本(当然 PythonINPLACE_ADD在第一个版本中使用操作码并且不查找__iadd__属性)。

但是,如您所见,名称var在这两个函数中加载一次并存储一次。因此,如果您分配一个变量,如常见问题解答所述,它是本地的,除非您首先将其声明为全局。

那么,如何加载一个尚不存在的局部变量进行求和1,然后以相同的名称再次存储?

类属性之所以起作用,是因为您正在执行以下操作:

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

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

于 2012-08-28T02:29:09.850 回答
1

我认为函数的前两行也不例外,因为引用了“Test”和“test”。

正确的。它们指的是 class 属性var,而不是您定义的全局属性。

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

或者换一种说法,Test并且test可以在全局命名空间中Test.var使用test.var

如果 中的值var未更改sum(),您将得到 0,因为它上面的行更改了Test类属性而不是全局属性。print在 sum 中添加一些s 并删除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 正在做一些“向前看”或检查variable scopesum(),因为它在重新评估print var之前引发了第一个错误。放置而不是引发相同的错误。)varvar = 50var += 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

输出:

1
2
0    # notice that global var is still 0 because the above var+=1 are for Test.var
1

编辑:关于我提到的“向前看”行为。本来要发布一个关于它的问题,但在这个答案中已经很好地解释了:https ://stackoverflow.com/a/370380/1431750 (到Python 变量范围错误

于 2012-08-28T02:48:16.557 回答
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
于 2012-08-28T02:40:10.213 回答