命名空間表示標(biāo)識(shí)符(identifier)的可見范圍,當(dāng)前命名空間主要是通過(guò)Python字典實(shí)現(xiàn)的,不過(guò)通常不關(guān)心具體的實(shí)現(xiàn)方式(除非出于性能考慮),以后也有可能會(huì)改變其實(shí)現(xiàn)方式。有一些命名空間的例子:內(nèi)置命名(像abs()這樣的函數(shù),以及內(nèi)置異常名)集,模塊中的全局命名,函數(shù)調(diào)用中的局部命名。某種意義上講對(duì)象的屬性集也是一個(gè)命名空間。有幾個(gè)點(diǎn)需要注意下:
第一:不同命名空間中的命名沒有任何聯(lián)系,例如兩個(gè)不同的模塊可能都會(huì)定義一個(gè)名為maximize的函數(shù)而不會(huì)發(fā)生混淆--用戶必須以模塊名為前綴來(lái)引用它們。
第二:不同的命名空間在不同的時(shí)刻創(chuàng)建,有不同的生存期。包含內(nèi)置命名的命名空間在Python解釋器啟動(dòng)時(shí)創(chuàng)建,會(huì)一直保留,不被刪除。模塊的全局命名空間在模塊定義被讀入時(shí)創(chuàng)建,通常,模塊命名空間也會(huì)一直保存到解釋器退出。由解釋器在最高層調(diào)用執(zhí)行的語(yǔ)句,不管它是從腳本文件中讀入還是來(lái)自交互式輸入,都是__main__模塊的一部分,所以它們也擁有自己的命名空間。(內(nèi)置命名也同樣被包含在一個(gè)模塊中,它被稱作__builtin__。)
第三:當(dāng)調(diào)用函數(shù)時(shí),就會(huì)為它創(chuàng)建一個(gè)局部命名空間,并且在函數(shù)返回或拋出一個(gè)并沒有在函數(shù)內(nèi)部處理的異常時(shí)被刪除。(實(shí)際上,用遺忘來(lái)形容到底發(fā)生了什么更為貼切。)當(dāng)然,每個(gè)遞歸調(diào)用都有自己的局部命名空間。
作用域是定義程序該如何搜索確切地“名字-對(duì)象”的名空間的層級(jí)關(guān)系。是一個(gè)Python程序可以直接訪問(wèn)命名空間的正文區(qū)域。意思是一個(gè)對(duì)名稱的錯(cuò)誤引用會(huì)嘗試在命名空間內(nèi)查找。盡管作用域是靜態(tài)定義,在使用時(shí)他們都是動(dòng)態(tài)的。每次執(zhí)行時(shí),至少有四個(gè)命名空間可以直接訪問(wèn)的作用域嵌套在一起:
第一:innermostscope,包含局部命名的使用域在最里面,首先被搜索;
第二:enclosingscope,中層的作用域,是內(nèi)層嵌套作用域搜索起點(diǎn),包含非局部,但是也非全局的命名
第三:Globalscope,包含當(dāng)前模塊的全局命名
第四:Built-inscope,包含內(nèi)置命名的命名空間。
so,這么多的作用域,Python是按什么順序搜索對(duì)應(yīng)作用域的呢?著名的”LEGB-rule”,即scope的搜索順序:Local->Enclosing->Global->Built-in;當(dāng)有一個(gè)變量在local域中找不到時(shí),Python會(huì)找上一層的作用域,即enclosing域(該域不一定存在)。enclosing域還找不到的時(shí)候,再往上一層,搜索模塊內(nèi)的global域。最后,會(huì)在built-in域中搜索。對(duì)于最終沒有搜索到時(shí),Python會(huì)拋出一個(gè)NameError異常。作用域可以嵌套。比如模塊導(dǎo)入時(shí)。這也是為什么不推薦使用froma_moduleimport*的原因,導(dǎo)入的變量可能被當(dāng)前模塊覆蓋。下面是一個(gè)例子:
defouter():
a=0
b=1
definner():
printa
printb
b=4
inner()
if__name__=="__main__":outer()
Traceback(mostrecentcalllast):
File"E:/PycharmProjects/CodeStatisticsTools/test_namespaces.py",line37,in
outer()
File"E:/PycharmProjects/CodeStatisticsTools/test_namespaces.py",line18,inouter
inner()
File"E:/PycharmProjects/CodeStatisticsTools/test_namespaces.py",line15,ininner
printb
UnboundLocalError:localvariable'b'referencedbeforeassignment
如果去掉b=4就能正常運(yùn)行,這是為啥呢?在沒有b=4這行代碼時(shí),Python解釋器執(zhí)行到inner()中的printb時(shí),發(fā)現(xiàn)有個(gè)變量b在當(dāng)前作用域(local)中無(wú)法找到變量b,于是嘗試從enclosingscope中查找,找到后就能正常打印了。加上這行代碼后,在當(dāng)前作用域找到了b,但是變量b的賦值發(fā)生在print語(yǔ)句之后,于是拋出錯(cuò)誤:變量在賦值前就被引用。賦值語(yǔ)句通常隱式地會(huì)創(chuàng)建一個(gè)局部(local)變量,即便該變量名已存在于賦值語(yǔ)句發(fā)生的上一層作用域中
以上內(nèi)容為大家介紹了python命名空間和作用域,希望對(duì)大家有所幫助,如果想要了解更多Python相關(guān)知識(shí),請(qǐng)關(guān)注IT培訓(xùn)機(jī)構(gòu):千鋒教育。