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,就会报错,为什么?
PHP中文网2017-04-18 09:31:09
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 b
assignment
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 的變量 b
而 b = 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 describingb
, Python will treat b
in test
as a variable to access global< code>b 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 assignment
Result:
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!
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
If a local variable is defined, Python will not look for the global variable, otherwise Python will automatically use the global vairable
If local vairable is defined but you read the reference before the variable is assigned, an UnboundLocalError will appear
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)
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
PHP中文网2017-04-18 09:31:09
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
天蓬老师2017-04-18 09:31:09
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
伊谢尔伦2017-04-18 09:31:09
Not found in your test1
函数有赋值操作x += 1
, 被Python解释器认为是函数本地作用域的变量, 但是该变量x
在赋值之前并没有被定义, 而且x
是number
, 属于不可变类型, 针对不可变类型的赋新值, 需要重新创建一个不可变类型的对象,并将原来的变量重新指向新创建的对象, 但是这个新创建的对象在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 = 3
for example):
Create an object to represent the value3
Create a variablea
, if it hasn’t been created yet
Connect the variable a
与新的对象3
to the new object
test2
函数在执行过程中变量y
Let’s observe your
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
的内存地址并不相同, 这也就可以解释str
或number
You can seethat all errors will be reported🎜