Python 程式設計/作用域
外觀
Python 中的變數透過賦值自動宣告。變數始終是對物件的引用,並且永遠不會被型別化。變數僅存在於當前作用域或全域性作用域中。當它們超出作用域時,變數會被銷燬,但它們引用的物件不會(除非對該物件的引用數量降至零)。
作用域由函式和類塊定義。函式及其作用域都可以巢狀。因此
def foo():
def bar():
x = 5 # x is now in scope
return x + y # y is defined in the enclosing scope later
y = 10
return bar() # now that y is defined, bar's scope includes y
現在測試這段程式碼時,
>>> foo()
15
>>> bar()
Traceback (most recent call last):
File "<pyshell#26>", line 1, in -toplevel-
bar()
NameError: name 'bar' is not defined
找不到名稱“bar”,因為較高級別的作用域無法訪問層次結構中較低級別的名稱。
在使用之前沒有將物件分配給變數是一個常見的陷阱。最常見的形式是
>>> for x in range(10):
y.append(x) # append is an attribute of lists
Traceback (most recent call last):
File "<pyshell#46>", line 2, in -toplevel-
y.append(x)
NameError: name 'y' is not defined
在這裡,要糾正此問題,必須在 for 迴圈執行之前新增 y = []。
迴圈不會建立自己的作用域
for x in [1, 2, 3]:
inner = x
print(inner) # 3 rather than an error
Python 模組的全域性變數可以從該模組中的函式中讀取。實際上,如果它們是可變的,它們也可以透過方法呼叫進行修改。但是,除非在函式中宣告為global,否則它們不能透過簡單的賦值進行修改。
一個例子來澄清
count1 = 1
count2 = 1
list1 = []
list2 = []
def test1():
print(count1) # Read access is unproblematic, referring to the global
def test2():
try:
print(count1) # This try block is problematic because...
count1 += 1 # count1 += 1 causes count1 to be local but local version is undefined.
except UnboundLocalError as error:
print("Error caught:", error)
def test3():
list1 = [2] # No outside effect; this defines list1 to be a local variable
def test4():
global count2, list2
print(count1) # Read access is unproblematic, referring to the global
count2 += 1 # We can modify count2 via assignment
list1.append(1) # Impacts the global list1 even without global declaration since its a method call
list2 = [2] # We can modify list2 via assignment
test1()
test2()
test3()
test4()
print("count1:", count1) # 1
print("count2:", count2) # 2
print("list1:", list1) # [1]
print("list2:", list2) # [2]
連結
- 6.13. The global statement,docs.python.org
- Python 中區域性變數和全域性變數的規則是什麼? 在程式設計常見問題解答中,docs.python.org
關鍵字 nonlocal,從 Python 3.0 開始可用,是global 在巢狀作用域中的類似物。它使巢狀函式能夠分配修改甚至是外部函式中區域性的不可變變數。
一個例子
# Requires Python 3
def outer():
outerint = 0
outerint2 = 10
def inner():
nonlocal outerint
outerint = 1 # Impacts outer's outerint only because of the nonlocal declaration
outerint2 = 1 # No impact
inner()
print(outerint)
print(outerint2)
outer()
Python 2 中使用可變物件模擬 nonlocal
def outer():
outerint = [1] # Technique 1: Store int in a list
class outerNL: pass # Technique 2: Store int in a class
outerNL.outerint2 = 11
def inner():
outerint[0] = 2 # List members can be modified
outerNL.outerint2 = 12 # Class members can be modified
inner()
print(outerint[0])
print(outerNL.outerint2)
outer()
連結
- 7.13. The nonlocal statement,docs.python.org
要找出全域性作用域和區域性作用域中存在哪些變數,可以使用locals() 和globals() 函式,它們返回字典
int1 = 1
def test1():
int1 = 2
globals()["int1"] = 3 # Write access seems possible
print(locals()["int1"])# 2
test1()
print(int1) # 3
Python 文件建議不要對 locals() 字典進行寫操作。
連結
- 2. 內建函式 # globals,docs.python.org
- 2. 內建函式 # locals,docs.python.org
- 4. 執行模型,docs.python.org
- 7.13. The nonlocal statement,docs.python.org
- PEP 3104 -- 訪問外部作用域中的名稱,python.org