python的作用域问题
高洛峰
高洛峰 2017-04-18 09:29:09
0
4
750
x = 3
y = [3]

def test1():
    x += 1
    print x

def test2():
    y[0] = 4
    y.append(5)
    print y

test2()
test1()

这段代码执行结果: test2()成功打印[4, 5], test1()却报错: UnboundLocalError: local variable 'x' referenced before assignment

想不明白,为什么会这样,全局变量在函数里可以直接打印,但是如果要改变它的值,会报错,但是test2()为什么不报错?如果把y换成dict类型,就能在函数里不需要用global声明,可以直接改变y的值,但如果是str或number,就会报错,为什么?

高洛峰
高洛峰

拥有18年软件开发和IT教学经验。曾任多家上市公司技术总监、架构师、项目经理、高级软件工程师等职务。 网络人气名人讲师,...

reply all(4)
洪涛

In fact, this question can be put aside whether the object referenced by the variable is mutable or immutable. What we need to pay attention to is the positioning of the variable, the time point and scope of the definition.

Consider the following code:

def test(a):
    print(a)
    print(b)
    
test(1)

This code will throw an error:

1
Traceback (most recent call last):
  File "tp.py", line 5, in <module>
    test(1)
  File "tp.py", line 3, in test
    print(b)
NameError: name 'b' is not defined

a 是 function test 的 param variable, 所以它屬於一個 local variable, 他的作用域是 test 函數, 我們將 1 傳進去讓 a 參考, 所以 print(a) 沒有什麼大問題。
但是 b 從頭到尾都沒定義, 即使依據 LEGB 原則去尋找也遍尋不著, 所以 raise 了一個 NameError.

To solve this problem, maybe we can define a global variable:

b = 100

def test(a):
    print(a)
    print(b)
    
test(1)

Great, it looks fine this time because Python found b, Python 之所以會使用 global b 那是因為在 local 我們並沒有定義 b in the global scope.

Then we start assigning values ​​to variables in the function:

b = 100

def test(a):
    b = 20
    print(a)
    print(b)
    
test(1)
print(b)

Result:

1
20
100

The two print within the function printed out 1 and 20 not surprisingly, but why did the value of b printed after leaving the function be 100?
Because we wrote such an print 不令人意外地印出了 1 跟 20, 但是為什麼離開 function 之後印出 b 的值是 100 呢?
因為我們在函數中寫了這樣一個 賦值 定義 b = 20, 所以在 test 中看到的 b 都是 local 的, 不是 global 的, 所以我們對 b 造成的任何更動都不會影響到 global bassignment

and

definition

b = 20 in the function, so the b seen in test are all It is local, not global, so any changes we make to b will not affect global b.

This tells us:

When local variable is not defined, Python will automatically use global variable, but not vice versaglobal

Then how can we operate global variables within the function? This requires the assistance of global 關鍵字 對 b 做了說明, Python 會將 test 中的 b 當作是要存取 global 的變量 bb = 20 this keyword:

b = 100

def test(a):
    global b
    b = 20
    print(a)
    print(b)
    
test(1)
print(b)
1
20
20

With the

keyword describing b, Python will treat b in test as a variable to access globalb and b = 20 will only be treated as an assignment action and will not define a new local variable.

Then let’s look at a more confusing example:

b = 100

def test(a):
    print(a)
    print(b)
    b = 20
    
test(1)
print(b)
UnboundLocalError, 為什麼會這樣呢? 原因很簡單, b 在這個函數內出現了賦值兼定義的動作: b = 20, 所以 test 內的 b 都是 local 的(在這裡並沒有使用 global 來指明 b 是 global 的), 所以當 print(b) 的時候, Python 會試圖去抓 local b 而不是 global b, 但是悲劇的是, 在這一步, local b 還沒被賦值, 所以才會說 local variable 'b' referenced before assignmentResult:
1
Traceback (most recent call last):
  File "tp.py", line 8, in <module>
    test(1)
  File "tp.py", line 5, in test
    print(b)
UnboundLocalError: local variable 'b' referenced before assignment

appears here

is referenced before being assigned, so naturally it won’t work. 🎜 🎜Look back at the example you gave:🎜
x = 3

def test1():
    x += 1
    print x

Here, when test1 中有 x 的定義發生 (沒有 global, 且 x 出現在等號左邊), 自然在參考 x, you will want to use local, but because:

x += 1 等義 x = x + 1

So when I want to get the value of the x reference on the right side of the equal sign, I find that it has not been assigned a value yet! Then this is the same as the above example:

UnboundLocalError: local variable 'x' referenced before assignment

As for your test2 no problem:

y = [3]

def test2():
    y[0] = 4
    y.append(5)
    print y

Because y does not appear on the left side of the equal sign in test2 中出現在等號左邊, 所以 Python 自動認定使用 global 的 y, so Python automatically assumes that global y is used, so naturally there is no problem!

Conclusion

  1. Observe whether local vairable is defined in a function and see if the variable name appears on the left side of the equal sign, and the variable name is not specified by global

  2. If a local variable is defined, Python will not look for the global variable, otherwise Python will automatically use the global vairable

  3. If local vairable is defined but you read the reference before the variable is assigned, an UnboundLocalError will appear

  4. To solve this problem, please remember to add global to specify the entire domain, otherwise this writing method should not appear (in-place operation, or assignment later)

  5. Similar problems will also occur in local function. The solution is to add nonlocal (Python3), but that is another story.


Questions I answered: Python-QA

洪涛

Python's variable scope is stipulated in this way. In test1, it can print x but cannot modify x
Some people say "global variables in local scope should be read-only", but this condition is not met for reference variables. . .

This place of python is really confusing

Peter_Zhu

Simply put, the binding of global variables cannot be changed in the local scope, and the address of the variable cannot be changed in CPython.

See: Common Mistake 4 in: The Ten Most Common Mistakes Python Programmers Make: Misunderstanding Variable Name Parsing in Python

伊谢尔伦

Not found in your test1函数有赋值操作x += 1, 被Python解释器认为是函数本地作用域的变量, 但是该变量x在赋值之前并没有被定义, 而且xnumber, 属于不可变类型, 针对不可变类型的赋新值, 需要重新创建一个不可变类型的对象,并将原来的变量重新指向新创建的对象, 但是这个新创建的对象在LEGB, so an error will be reported

test2函数中, y是个list, It is a variable type. After append, the list still points to the same memory address. Because the list is a variable type, it can be modified in place, so no error will be reported

Python中所有赋值操作基本都分为下面三个步骤(以a = 3for example):

  1. Create an object to represent the value3

  2. Create a variablea, if it hasn’t been created yet

  3. Connect the variable a与新的对象3 to the new object

test2函数在执行过程中变量yLet’s observe your

memory address changes

y = [3]
print(id(y))
def test2():
    y[0] = 4
    print(id(y))
    y.append(5)
    print(id(y))
    print(y)
    
test2()
x = 3
print(id(x))
x = 4
print(id(x))
Output

79051032
79051032
79051032
[4, 5]
1375754544
1375754560
y其实是在原地修改的, 所以不需要重复创建变量; 而对于x不可变类型来说, 要给他赋值, 就必须先创建一个新的对象, 即使名字一样, 可以看到其实如果每次不同的赋值, 实际上x的内存地址并不相同, 这也就可以解释strnumberYou can seethat all errors will be reported🎜
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template