在本文中,您將了解命名空間,從名稱到對象的映射以及變量的作用域。
如果您曾經(jīng)讀過“ Python之禪(The Zen of Python) ”(在Python解釋器中輸入import this),最后一行指出,命名空間是一個很棒的主意-讓我們做更多的事情!那么這些神秘的命名空間是什么?首先讓我們看看名稱是什么。
名稱(也稱為標識符)只是賦予對象的名稱。Python中的一切都是對象。名稱是訪問基礎(chǔ)對象的一種方式。
例如,當我們執(zhí)行賦值操作時a = 2,2是一個存儲在內(nèi)存中的對象,而a是與之關(guān)聯(lián)的名稱。我們可以通過內(nèi)置函數(shù) 獲取某些對象的地址(在RAM中)id()。讓我們看看如何使用它。
# 注意:您可能會得到不同的id值 a = 2 print('id(2) =', id(2)) print('id(a) =', id(a))
輸出結(jié)果
id(2) = 9302208 id(a) = 9302208
在這里,兩者都引用相同的對象2,因此它們具有相同的id()。讓我們做些有趣的事情。
# 注意:您可能會得到不同的id值 a = 2 print('id(a) =', id(a)) a = a+1 print('id(a) =', id(a)) print('id(3) =', id(3)) b = 2 print('id(b) =', id(b)) print('id(2) =', id(2))
輸出結(jié)果
id(a) = 9302208 id(a) = 9302240 id(3) = 9302240 id(b) = 9302208 id(2) = 9302208
上述步驟序列中發(fā)生了什么?讓我們用一個圖來解釋一下:
最初,創(chuàng)建一個對象2并將名稱a與之相關(guān)聯(lián),當我們執(zhí)行a = a + 1時,將創(chuàng)建一個新的對象3,現(xiàn)在a與該對象相關(guān)聯(lián)。
請注意,id(a)和id(3)具有相同的值。
此外,當執(zhí)行b = 2時,新名稱b與先前的對象2相關(guān)聯(lián)。
這是有效的,因為Python不必創(chuàng)建新的重復對象。 名稱綁定的這種動態(tài)特性使Python變得功能強大。 名稱可以引用任何類型的對象。
>>> a = 5 >>> a = 'Hello World!' >>> a = [1,2,3]
所有這些都是有效的,并且a將在不同示例中引用三種不同類型的對象。函數(shù)也是對象,因此名稱也可以引用它們。
def printHello(): print("Hello") a = printHello a()
輸出結(jié)果
Hello
相同的名稱a可以引用一個函數(shù),我們可以使用該名稱來調(diào)用該函數(shù)。
現(xiàn)在我們了解了名稱是什么,我們可以繼續(xù)進行命名空間的概念。
簡而言之,命名空間是名稱的集合。
在Python中,您可以將命名空間想象為已定義的每個名稱到對應對象的映射。
不同的命名空間可以在給定時間共存,但完全隔離。
當我們啟動Python解釋器時,將創(chuàng)建一個包含所有內(nèi)置名稱的命名空間,并且只要該解釋器運行,該命名空間就會存在。
這就是為什么內(nèi)置的功能(例如id())print()等始終可以從程序的任何部分使用的原因。每個模塊創(chuàng)建自己的全局命名空間。
這些不同的命名空間是隔離的。因此,不同模塊中可能存在的相同名稱不會沖突。
模塊可以具有各種功能和類。調(diào)用函數(shù)時會創(chuàng)建一個本地命名空間,其中定義了所有名稱。與類相似。下圖可能有助于闡明這一概念。
盡管定義了各種唯一的命名空間,但我們可能無法從程序的每個部分訪問它們。作用域的概念開始起作用。
作用域是程序的一部分,從那里可以直接訪問命名空間而無需任何前綴。
在任何給定時刻,至少有三個嵌套作用域。
具有本地名稱的當前函數(shù)的作用域
具有全局名稱的模塊的作用域
具有內(nèi)置名稱的最外部作用域
在函數(shù)內(nèi)部進行引用時,將在本地命名空間中搜索名稱,然后在全局命名空間中搜索,最后在內(nèi)置命名空間中搜索。
如果另一個函數(shù)內(nèi)有一個函數(shù),則新作用域嵌套在本地作用域內(nèi)。
def outer_function(): b = 20 def inner_func(): c = 30 a = 10
在這里,變量a在全局命名空間中。變量b在的本地命名空間中,outer_function()而c在的嵌套本地命名空間中inner_function()。
當我們在時inner_function(),c在我們本地,b在非本地,a在全局。我們可以為c讀取和分配新值,但只能 從中讀取b和ainner_function()。
如果我們嘗試分配作為值b,一個新的變量b在本地命名空間比非本地不同的創(chuàng)建b。當我們分配一個值,同樣的事情發(fā)生一個。
但是,如果我們將a聲明為全局a,則所有引用和賦值都將移至全局a。同樣,如果我們想重新綁定變量b,則必須將其聲明為非本地變量。以下示例將進一步闡明這一點。
def outer_function(): a = 20 def inner_function(): a = 30 print('a =', a) inner_function() print('a =', a) a = 10 outer_function() print('a =', a)
正如您看到的,該程序的輸出為
a = 30 a = 20 a = 10
在此程序中,在不同的命名空間中定義了三個不同的變量a并進行了相應的訪問。在以下程序中,
def outer_function(): global a a = 20 def inner_function(): global a a = 30 print('a =', a) inner_function() print('a =', a) a = 10 outer_function() print('a =', a)
程序的輸出是。
a = 30 a = 30 a = 30
在這里,由于使用了關(guān)鍵字global,所以所有引用和賦值都指向全局a。