简体   繁体   English

Python中的局部,全局和对象

[英]Local, Global and objects in Python

I have a question about local and global variables and global objects in Python. 我对Python中的局部和全局变量以及全局对象有疑问。 Look at this code: 看这段代码:

var = 0

class Test():
    var = 0

test = Test()

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

sum()

If I run that code, the exception is triggered in the line "var += 1" only. 如果运行该代码,则仅在“ var + = 1”行中触发异常。 The two previous lines work. 前两行有效。 I read this question from the Python FAQ. 我从Python FAQ中阅读了这个问题 I think that there is no exception in the first two lines of the function because the "Test" and "test" are referenced. 我认为函数的前两行也没有例外,因为引用了“测试”和“测试”。 The member "var" is assigned, but "Test" and "test" are global because are referenced to get the member. 成员“ var”已分配,但“ Test”和“ test”是全局的,因为被引用以获取成员。 The FAQ said: "In Python, variables that are only referenced inside a function are implicitly global. If a variable is assigned a new value anywhere within the function's body, it's assumed to be a local." 常见问题解答说:“在Python中,仅在函数内部引用的变量是隐式全局的。如果在函数体内的任何位置为变量分配了新值,则假定该变量是局部变量。”

So, the question is... is my assumption true? 所以,问题是……我的假设是真的吗?

Look at these functions: 查看以下功能:

def f():
    var += 1

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

g is the literal version of what the f function does (Of course Python uses the INPLACE_ADD opcode in the first version and do not lookup for the __iadd__ attribute). gf函数执行的字面版本(当然,Python在第一个版本中使用INPLACE_ADD操作码,并且不查找__iadd__属性)。

But, as you can see, the name var is loaded once and stored once in both these functions. 但是,正如您所看到的,名称var在这两个函数中均被加载一次并存储一次。 So, if you assign a variable, as the FAQ says, it is local unless you declare it global first. 因此,如果您分配一个变量(如FAQ所述),则除非您先声明全局变量,否则它是局部变量。

Then, how can you load a local variable that do not exists yet to sum 1 and then store again with the same name? 然后,如何加载尚不存在的局部变量求和1 ,然后再次使用相同名称存储?

The class attributes work because you are doing: 之所以使用类属性是因为您正在执行以下操作:

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

and var do exist in the Test scope (so it can be looked up and reassigned). var确实存在于Test范围内(因此可以对其进行查找和重新分配)。

I think that there is no exception in the first two lines of the function because the "Test" and "test" are referenced. 我认为函数的前两行也没有例外,因为引用了“测试”和“测试”。

Correct. 正确。 And they refer to the class attribute var , not the global one you defined. 它们引用的是class属性var ,而不是您定义的全局属性。

The member "var" is assigned, but "Test" and "test" are global because are referenced to get the member. 成员“ var”已分配,但“ Test”和“ test”是全局的,因为被引用以获取成员。

Or to put it another way, Test and test are available in the global namespace so Test.var and test.var work. 换句话说, Testtest在全局名称空间中可用,因此Test.vartest.var工作。

If the value of var was not changed in sum() , you would get 0 since the lines above it have changed the Test class attribute not the global. 如果var的值未在sum()更改,则将获得0,因为它上面的行更改了Test类属性,而不是全局属性。 Adding some print s in sum and removing the var += 1 总和添加一些print并删除var += 1

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

sum()

...gives: ...给出:

1
2
0

But the moment I try to assign a value to var within the sum function, I get an error even before that line: 但是,当我尝试在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

Because var is now being assigned a value in sum(), it's considered local but has not been defined prior to that line. 由于var现在在sum()中分配了一个值,因此将其视为本地值,但尚未在该行之前定义。 (Which implies that python is doing some 'looking ahead' or checking variable scope in sum() since it raised the error for the first print var before var was re-assinged. Putting var = 50 instead of var += 1 raises the same error.) (这意味着Python是做一些“向前看”或检查variable scope的总和(),因为它提出了第一个错误print var之前var重新assinged。把var = 50 ,而不是var += 1提出了一个相同的错误。)

To work with the global var: 要使用全局变量:

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

output: 输出:

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

Edit: Regarding the 'look ahead' behaviour I mentioned. 编辑:关于我提到的“展望未来”行为。 Was going to post a question about it but it's been explained well in this answer: https://stackoverflow.com/a/370380/1431750 (to Python variable scope error ) 打算发布一个关于它的问题,但是这个答案已经很好地解释了: https : //stackoverflow.com/a/370380/1431750 (到Python变量作用域错误

In essence the rules are to avoid ambiguity: 本质上,规则是避免歧义:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM