分四部分揭示Python命名空間的本質(zhì):
一躏鱼、命名空間的定義
Python使用叫做命名空間的東西來(lái)記錄變量的軌跡蜕窿。命名空間是一個(gè) 字典(dictionary) 谋逻,它的鍵就是變量名,它的值就是那些變量的值桐经。
A namespace is a mapping from names to objects. Most namespaces are currently implemented as Python dictionaries毁兆。
在一個(gè) Python 程序中的任何一個(gè)地方,都存在幾個(gè)可用的命名空間阴挣。
1气堕、每個(gè)函數(shù)都有著自已的命名空間,叫做局部命名空間畔咧,它記錄了函數(shù)的變量茎芭,包括函數(shù)的參數(shù)和局部定義的變量。
2誓沸、每個(gè)模塊擁有它自已的命名空間梅桩,叫做全局命名空間,它記錄了模塊的變量蔽介,包括函數(shù)摘投、類、其它導(dǎo)入的模塊虹蓄、模塊級(jí)的變量和常量犀呼。
3、還有就是內(nèi)置命名空間薇组,任何模塊均可訪問(wèn)它外臂,它存放著內(nèi)置的函數(shù)和異常。
二律胀、命名空間的查找順序
當(dāng)一行代碼要使用變量 x 的值時(shí)宋光,Python 會(huì)到所有可用的名字空間去查找變量,按照如下順序:
1炭菌、局部命名空間:特指當(dāng)前函數(shù)或類的方法罪佳。如果函數(shù)定義了一個(gè)局部變量 x,或一個(gè)參數(shù) x黑低,Python 將使用它赘艳,然后停止搜索酌毡。
2、全局命名空間:特指當(dāng)前的模塊蕾管。如果模塊定義了一個(gè)名為 x 的變量枷踏,函數(shù)或類,Python 將使用它然后停止搜索掰曾。
3旭蠕、內(nèi)置命名空間:對(duì)每個(gè)模塊都是全局的。作為最后的嘗試旷坦,Python 將假設(shè) x 是內(nèi)置函數(shù)或變量掏熬。
4、如果 Python 在這些名字空間找不到 x塞蹭,它將放棄查找并引發(fā)一個(gè) NameError 異常孽江,如,NameError: name 'aa' is not defined番电。
嵌套函數(shù)的情況:
1、先在當(dāng)前 (嵌套的或 lambda) 函數(shù)的命名空間中搜索
2辆琅、然后是在父函數(shù)的命名空間中搜索
3漱办、接著是模塊命名空間中搜索
4、最后在內(nèi)置命名空間中搜索
示例:
info = "Adress : "
def func_father(country):
def func_son(area):
city= "Shanghai " #此處的city變量婉烟,覆蓋了父函數(shù)的city變量
print(info + country + city + area)
city = " Beijing "
#調(diào)用內(nèi)部函數(shù)
func_son("ChaoYang ");
func_father("China ")
輸出:Adress : China Shanghai ChaoYang
以上示例中娩井,info在全局命名空間中,country在父函數(shù)的命名空間中似袁,city洞辣、area在自己函數(shù)的命名空間中
三、命名空間的生命周期
不同的命名空間在不同的時(shí)刻創(chuàng)建昙衅,有不同的生存期扬霜。
1、內(nèi)置命名空間在 Python 解釋器啟動(dòng)時(shí)創(chuàng)建而涉,會(huì)一直保留著瓶,不被刪除。
2啼县、模塊的全局命名空間在模塊定義被讀入時(shí)創(chuàng)建材原,通常模塊命名空間也會(huì)一直保存到解釋器退出。
3季眷、當(dāng)函數(shù)被調(diào)用時(shí)創(chuàng)建一個(gè)局部命名空間余蟹,當(dāng)函數(shù)返回結(jié)果 或 拋出異常時(shí),被刪除子刮。每一個(gè)遞歸調(diào)用的函數(shù)都擁有自己的命名空間威酒。
Python 的一個(gè)特別之處在于其賦值操作總是在最里層的作用域。賦值不會(huì)復(fù)制數(shù)據(jù)——只是將命名綁定到對(duì)象。刪除也是如此:"del y" 只是從局部作用域的命名空間中刪除命名 y 兼搏。事實(shí)上卵慰,所有引入新命名的操作都作用于局部作用域。
i=1
def func2():
i=i+1
func2();
#錯(cuò)誤:UnboundLocalError: local variable 'i' referenced before assignment
由于創(chuàng)建命名空間時(shí)佛呻,python會(huì)檢查代碼并填充局部命名空間裳朋。在python運(yùn)行那行代碼之前,就發(fā)現(xiàn)了對(duì)i的賦值吓著,并把它添加到局部命名空間中鲤嫡。當(dāng)函數(shù)執(zhí)行時(shí),python解釋器認(rèn)為i在局部命名空間中但沒(méi)有值绑莺,所以會(huì)產(chǎn)生錯(cuò)誤暖眼。
def func3():
y=123
del y
print(y)
func3()
#錯(cuò)誤:UnboundLocalError: local variable 'y' referenced before assignment
#去掉"del y"語(yǔ)句后,運(yùn)行正常
四纺裁、通過(guò)locals()和globals() BIF訪問(wèn)命名空間
1诫肠、局部命名空間可以 locals() BIF來(lái)訪問(wèn)。
locals 返回一個(gè)名字/值對(duì)的 dictionary欺缘。這個(gè) dictionary 的鍵是字符串形式的變量名字栋豫,dictionary 的值是變量的實(shí)際值。
示例:
def func1(i, str ):
x = 12345
print(locals())
func1(1 , "first")
輸出:{'str': 'first', 'x': 12345, 'i': 1}
2谚殊、全局 (模塊級(jí)別)命名空間可以通過(guò) globals() BIF來(lái)訪問(wèn)丧鸯。
示例:
'''Created on 2013-5-26'''
import copy
from copy import deepcopy
gstr = "global string"
def func1(i, info):
x = 12345
print(locals())
func1(1 , "first")
if __name__ == "__main__":
print("the current scope's global variables:")
dictionary=globals()
print(dictionary)
輸出:
{
'name': 'main',
'doc': 'Created on 2013-5-26',
'package': None,
'cached': None,
'file': 'E:\WorkspaceP\Test1\src\base\test1.py',
'loader': <_frozen_importlib.SourceFileLoader object at 0x01C702D0>,
'copy': <module 'copy' from 'D:\Python33\lib\copy.py'>,
'builtins': <module 'builtins' (built-in)>,
'gstr': 'global string',
'dictionary': {...},
'func1': <function func1 at 0x01C6C540>,
'deepcopy': <function deepcopy at 0x01DB28A0>
}
- 總結(jié)
1、模塊的名字空間不僅僅包含模塊級(jí)的變量和常量嫩絮,還包括所有在模塊中定義的函數(shù)和類丛肢。除此以外,它還包括了任何被導(dǎo)入到模塊中的東西剿干。
2蜂怎、我們看到,內(nèi)置命名也同樣被包含在一個(gè)模塊中怨愤,它被稱作 builtin派敷。
3、回想一下 from module import 和 import module 之間的不同撰洗。
使用 import module篮愉,模塊自身被導(dǎo)入,但是它保持著自已的名字空間差导,這就是為什么您需要使用模塊名來(lái)訪問(wèn)它的函數(shù)或?qū)傩裕簃odule.function 的原因试躏。
但是使用 from module import function,實(shí)際上是從另一個(gè)模塊中將指定的函數(shù)和屬性導(dǎo)入到您自己的名字空間设褐,這就是為什么您可以直接訪問(wèn)它們卻不需要引用它們所來(lái)源的模塊颠蕴。使用 globals 函數(shù)泣刹,您會(huì)真切地看到這一切的發(fā)生,見(jiàn)上面的紅色輸出語(yǔ)句犀被。
3椅您、 locals 與 globals 之間的一個(gè)重要的區(qū)別
locals 是只讀的,globals 不是
def func1(i, info):
x = 12345
print(locals())
locals()["x"]= 6789
print("x=",x)
y=54321
func1(1 , "first")
globals()["y"]= 9876
print( "y=",y)
輸出:
{'i': 1, 'x': 12345, 'info': 'first'}
x= 12345
y= 9876
解釋:
locals 實(shí)際上沒(méi)有返回局部名字空間寡键,它返回的是一個(gè)拷貝掀泳。所以對(duì)它進(jìn)行改變對(duì)局部名字空間中的變量值并無(wú)影響。
globals 返回實(shí)際的全局名字空間西轩,而不是一個(gè)拷貝员舵。所以對(duì) globals 所返回的 dictionary 的任何的改動(dòng)都會(huì)直接影響到全局變量。
Ref:http://www.cnblogs.com/windlaughing/archive/2013/05/26/3100362.html