1. 程式人生 > >Python的變數作用域、名稱空間和作用域的區別、This inspection detects shadowing names defined in outer scopes警告解決

Python的變數作用域、名稱空間和作用域的區別、This inspection detects shadowing names defined in outer scopes警告解決

Python的變數作用域:

L(local)區域性作用域:

區域性變數:包含在def關鍵字定義的函式中,即在函式中定義的變數。每當函式被呼叫時都會建立一個新的區域性作用域。在函式內部的變數宣告,除非特別的使用global關鍵字宣告為其全域性變數,否則均預設為區域性變數。

區域性變數域就像一個棧,僅僅是暫時的存在,依賴建立該區域性作用域的函式是否處於活動的狀態。一般建議儘量少定義全域性變數,因為全域性變數在模組檔案執行的過程中會一直存在,佔用記憶體空間。 

注意:

如果需要在函式內部對全域性變數賦值,需要在函式內部通過global語句宣告該變數為全域性變數。

E(enclosing)巢狀作用域:

E作用域也在def關鍵字定義的函式中,E和L是相對的,E相對於更上層的函式而言也是L。與L的區別在於,對一個函式而言,L是定義在此函式內部的區域性作用域,而E是定義在此函式的上一層父級函式的區域性作用域

G(global)全域性作用域:

即在模組層次中定義的變數,每一個模組都是一個全域性作用域。也就是說,在模組檔案頂層宣告的變數具有全域性作用域,從外部開來,模組的全域性變數就是一個模組物件的屬性。 

注意:

全域性作用域的作用範圍僅限於單個模組檔案內。

B(built-in)內建作用域:

系統內固定模組裡定義的變數,如預定義在__builtin__ 模組內的變數。

舉例:

x = int(2.9)  # 內建作用域B

g_count = 0  # 全域性作用域G


def outer():
	o_count = 1  # 閉包函式外的函式中巢狀作用域E

	def inner():
		i_count = 2  # 區域性作用域L

LEGB法則:

當在函式中使用未確定的變數名時,搜尋變數名順序的優先順序:

區域性作用域(L) > 巢狀作用域 (E)> 全域性作用域 (B)> 內建作用域(B) 

如果都搜尋完了還沒有找到,則會發出NameError錯誤。

建立一個新的作用域:

在python中,模組(module),類(class)、函式(def、lambda)會產生新的作用域,其他程式碼塊是不會產生作用域的,也就是說,類似條件判斷(if…..else)、迴圈語句(for x in data)、異常捕捉(try…catch)等的變數是可以全域性使用的

如:

dataList = [1, 2, 3, 4]
for data in dataList:
	a = 1  # for迴圈中的變數a
	b = data + a

print(a)  # 在函式外也可視為全域性變數使用

名稱空間和作用域的區別:

名稱空間:

是一個包含了該空間中所有變數和變數值的字典,不同的名稱空間之間是相互隔離的,所以在不同的名稱空間可以建立同名變數,通過句點識別符號來呼叫和區別。如EG. JmilkFan.name & fanguiju.name JmilkFan 和 fanguiju 是兩個不同的名稱空間

Python 內建了兩個查詢名稱空間的字典的內建函式: globals()和locals()。

如:

a = 1


def add():
	x = 2
	x = x + 2
	print(x)


print(globals())
print(locals())

執行結果如下:

{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x00000000023FB080>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'F:/0 system backup/desktop/data/testpython/test.py', '__cached__': None, 'a': 1, 'add': <function add at 0x0000000002351EA0>}
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x00000000023FB080>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'F:/0 system backup/desktop/data/testpython/test.py', '__cached__': None, 'a': 1, 'add': <function add at 0x0000000002351EA0>}
4

Process finished with exit code 0

注意:

根據呼叫地方的不同,globals()和locals()函式可被用來返回全域性和區域性名稱空間裡的名字;

如果在函式內部呼叫locals(),返回的是所有能在該函式裡訪問的命名;

如果在函式內部呼叫globals(),返回的是所有在該函式裡能訪問的全域性名字;

兩個函式的返回型別都是字典。所以能用keys()函式取得變數名。

作用域:

作用域是一個變數有效的區域,全域性作用域的全域性變數在整個模組中有效,區域性作用域中的區域性變數只在類或函式中有效。

作用域和名稱空間的關係:

建立一個作用域會同時生成一個名稱空間,並且作用域包圍了其名稱空間。作用域是為了實現變數查詢的路徑,如果區域性作用域中含有與全域性作用域同名的變數時,區域性作用域會遮蔽掉全域性作用域,這是因為變數的查詢路徑中,區域性作用域要先於全域性作用域,然後再到相對的名稱空間中獲取變數的值。

This inspection detects shadowing names defined in outer scopes警告的解決:

當我們在一個函式體外部定義了一個變數名,而def一個函式體時傳入的變數又與這個外部定義的變數名同名時,就會出現上面的警告。

這時有兩種解決方法:

1、如果我們的函式確實想修改外部變數:

如:

我們定義了一個外部變數a,如果我們確實想修改a,那麼就在函式體內用global關鍵字把a宣告為全域性變數。

a = 1


def add():
	global a
	a = a + 1


add()
print(a)

2、我們的函式只想傳入外部變數的值:

如:

那麼我們就在def函式時使用另外一個名字作為區域性變數,然後呼叫該函式時將a變數的值傳入。

a = 1


def add(num):
	b = num + 2
	print(b)


add(a)