我对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中,仅在函数内引用的变量是隐式全局的。如果在函数体内的任何位置为变量赋值,则假定它是本地的。”
所以,问题是......我的假设是真的吗?
答案 0 :(得分:2)
看看这些功能:
def f():
var += 1
def g():
var = var.__iadd__(1)
g
是f
函数的文字版本(当然Python在第一个版本中使用INPLACE_ADD
操作码而不查找__iadd__
属性)。
但是,正如您所看到的,名称var
被加载一次并在这两个函数中存储一次。因此,如果你分配一个变量,就像FAQ所说的那样,它是本地变量,除非你先将它声明为全局变量。
那么,如何加载一个尚不存在的局部变量来汇总1
,然后再次存储同名?
类属性有效,因为您正在执行:
Test.var = Test.var.__iadd__(1)
和var
确实存在于Test
范围内(因此可以查找并重新分配)。
答案 1 :(得分:1)
我认为前两行中没有例外 函数,因为引用了“测试”和“测试”。
正确。它们引用了类属性var
,而不是您定义的全局属性。
分配成员“var”,但“Test”和“test”是全局的,因为引用它来获取成员。
或者换句话说,Test
和test
在全局命名空间中可用,因此Test.var
和test.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