Python名稱空間與作用域
阿新 • • 發佈:2020-08-03
名稱空間:
-
存放名字與值的關係的空間
-
在python直譯器開始執行, 就會在記憶體中開闢一個空間, 每當遇到一個變量的時候, 就把變量名和值之間的關係記錄下來,
-
當遇到函式定義的時候, 直譯器只是把函式名讀入記憶體, 並檢查語法是否正確,表示這個函式存在了, 至於函式內部的變量和邏輯, 直譯器是不關心的。
-
只有當函式被呼叫和訪問的時候, 直譯器才會根據函式內部宣告的變量來進行開闢變量的內部空間.
內建名稱空間:
- 存放Python直譯器內建的名字,如input,print,list等
- 存活週期:Python直譯器啟動則產生,Python直譯器關閉則銷燬
全域性名稱空間:
- 執行程式碼伊始所產生的名字,或者說不是函式內定義、也不是內建的剩下的都是全域性名稱空間
- 存活週期:Python檔案執行產生,檔案執行結束銷燬
臨時名稱空間:
- 在函式體的執行中開闢的臨時的空間,也叫做區域性名稱空間,同一個函式呼叫多次會產生多個區域性名稱空間。
- 存活週期:函式體執行時產生,函式執行結束,這個空間也會清空
載入到記憶體的順序:
-
1.內建名稱空間
-
2.全域性名稱空間
-
3.臨時名稱空間
取值順序:(就近原則:LEGB原則)單向不可逆
- (從區域性開始找時)區域性名稱空間 --> 全域性名稱空間 --> 內建名稱空間
input = 333 print(input) # 此時是從全域性開始取值,input()函式則不會被查詢到 # 333
LEGB原則:
- local本地 --> enclosed巢狀函式的外層函式內部 --> global全域性 --> buildin內建
def func(): print(x) x = 111 func() # 區域性沒有則在全域性查詢,在函式執行前x被賦值,所以並不會報錯 # 111 x = 1 def func(): print(x) def foo(): x = 222 func() foo() # 名稱空間的'巢狀'關係是以函式定義階段為準,與呼叫位置無關 # 1 input = 111 def f1(): def f2(): input = 333 print(input) input = 222 f2() f1() # 名稱空間的'巢狀'關係是以函式定義階段為準,與呼叫位置無關 # 333
注:名稱空間實際上是相互獨立的一個個空間,並沒有包含關係,巢狀關係僅為了幫助理解
作用域:
- 變數的生效範圍,分為全域性作用域和區域性作用域
全域性作用域:
- 內建名稱空間,全域性名稱空間,在整個檔案的任何位置都可以執行(遵循從上到下逐行執行)
區域性作用域:
- 區域性名稱空間,在函式內部可以使用。
- 區域性作用域可以引用全域性作用域的變數,但不可改變:
- 因為當Python讀取到區域性作用域時,發現對變數進行了更改,
直譯器會認為這個變數在區域性已經定義,就會從區域性名稱空間尋找這個變數,
然而區域性空間並沒有定義這個變數,所以報錯。
- 因為當Python讀取到區域性作用域時,發現對變數進行了更改,
count = 1
def func():
count = 100 # 這是在區域性名稱空間重新建立變數count,並非修改了全域性名稱空間的count
print(count)
func()
# 100
count = 1
def func():
count += 1 # 不可更改
print(count)
func()
# local variable 'count' referenced before assignment
高階函式:
- 函式內巢狀函式。
作用域相關的內建函式:
- globals():返回的是字典,裡面的鍵值對為全域性作用域的所有內容
print(globals())
- locals():返回的是字典,裡面的鍵值對為當前作用域的所有內容
print(globals())
函式中變數引用的坑:
- 在函式中,如果你定義了一個變數,但是在定義之前引用了此變數,那麼直譯器會認為,語法錯誤。應該在引用之前先定義。
count = 1
def func():
print(count)
count = 2
func()
# local variable 'count' referenced before assignment
關鍵字:
- global:
- 在區域性作用域宣告一個全域性變數。
- 如果區域性想要修改全域性的名字對應的值(不可變資料型別),也需要用global。
name = '杜甫'
def func():
global name # 變數賦值前先宣告name是全域性名稱,不要再造新名稱
name = '李白'
func() # 函式呼叫後,函式內宣告的全域性變數才生效
print(name)
# 李白
- 如果區域性想要修改全域性的名字對應的值(可變型別),則不需要global:
l1 = [111,222]
def func():
l1.append(333)
func()
print(l1)
# [111, 222, 333]
- nonlocal:
- 在巢狀函式中,內層函式對上一層函式內名稱的修改(不可變型別),需要nonlocal
- nonlocal的使用必須是內層函式對非全域性的外層函式,如果外層函式沒有找到被宣告的名稱,則會報錯
x = 0
def f1():
x = 11 # 如果f1內的x註釋掉,nonlocal則報錯
def f2():
nonlocal x
x = 22
f2()
print('f1內的x:',x)
f1()
# f1內的x: 22
x = 0
def f1():
x = [11,]
def f2():
x.append(22) # 如果是可變型別則不需要nonlocal,可直接修改
f2()
print('f1內的x:',x)
f1()
# f1內的x: [11, 22]