python中的作用域與命名空間

python中的幾個命名空間:
1.局部命名空間:包含局部變量
2.全局命名空間: 當前模塊的最外層的全局變量
3.內(nèi)置(built-in)命名空間: 包含了內(nèi)置的變量/關(guān)鍵字等

這三個命名空間分別有各自的生命周期:
1.局部命名空間:函數(shù)的局部命名空間术幔,在函數(shù)調(diào)用時創(chuàng)建,函數(shù)返回或者由未捕獲的異常時銷毀湃密;類定義的命名空間诅挑,在解釋器讀到類定義創(chuàng)建,類定義結(jié)束后銷毀
2.全局命名空間:模塊的全局命名空間在模塊定義被解釋器讀入時創(chuàng)建泛源,解釋器退出時銷毀
3.內(nèi)置命名空間:在Python解釋器啟動時創(chuàng)建拔妥,解釋器退出時銷毀

python代碼中查找一個變量按照LEGB的順序查找:
1.Local:首先搜索,包含局部名字的最內(nèi)層(innermost)作用域达箍,如函數(shù)/方法/類的內(nèi)部局部作用域没龙;
2.Enclosing:根據(jù)嵌套層次從內(nèi)到外搜索,包含非局部(nonlocal)非全局(nonglobal)名字的任意封閉函數(shù)的作用域缎玫。如兩個嵌套的函數(shù)硬纤,內(nèi)層函數(shù)的作用域是局部作用域,外層函數(shù)作用域就是內(nèi)層函數(shù)的 Enclosing作用域赃磨;
3.Global 倒數(shù)第二次被搜索筝家,包含當前模塊全局名字的作用域;
4.Built-in 最后被搜索邻辉,包含內(nèi)建名字的最外層作用域溪王。

>>> i=2
>>> def func():
...    print(i)
... 
>>> func()
2

注:程序運行過程中LGB一定存在,E不一定存在

>>> i=2
>>> print(i)
2

這種類型的程序恩沛,命令空間的說明如下:
<b>Usually, the local scope references the local names of the (textually) current function. Outside functions, the local scope references the same namespace as the global scope: the module's namespace. Class definitions place yet another namespace in the local scope.</b>

還有一個地方需要注意的是在扰;

>>> i=2
>>> def fun():
...     print(i)
...     i=3
>>> fun()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in fun
UnboundLocalError: local variable 'i' referenced before assignment

如果內(nèi)部函數(shù)有引用外部函數(shù)的同名變量或者全局變量,并且對這個變量有修改.那么python會認為它是一個局部變量,所以在print(i)時該變量還沒有定義雷客,出現(xiàn)UnboundLocalError芒珠。
那么如果需要修改global中的變量怎么辦呢?可以使用global關(guān)鍵字:

>>> i=2
>>> def func():
...   global i
...   print(i)
...   i=3
... 
>>> func()
2
>>> print(i)
3

在python3.X版本中引入了關(guān)鍵字nonlocal,用來在函數(shù)或其他作用域中使用外層(非全局)變量
(The nonlocal
statement causes the listed identifiers to refer to previously bound variables in the nearest enclosing scope. This is important because the default behavior for binding is to search the local namespace first. The statement allows encapsulated code to rebind variables outside of the local scope besides the global (module) scope搅裙。)

i=2
def func():
    i=3
    def func1():
        i=4
        nonlocal i
        print(i)
        i+=1
    return func1
a=func()
a()
print(i)
a()

---outputs---
4
2
4
/usercode/file3.py:7: SyntaxWarning: name 'i' is assigned to before nonlocal declaration
  nonlocal i
#!/usr/bin/python
i=2
def func():
    i=3
    def func1():
        nonlocal i
        print(i)
        i+=1
    return func1
a=func()
a()
print(i)
a()

---outputs---
3
2
4

python中內(nèi)置了locals和globals2個方法可以查詢局部和全局的命名空間

#!/usr/bin/python
i=2
def func():
    j=4
    print("locals:",locals())
print("globals:",globals())
func()

---outputs---
globals: {'__loader__': <_frozen_importlib.SourceFileLoader object at 0x7fb1ce70f0b8>, 
'__spec__': None, '__name__': '__main__', '__cached__': None,
'__builtins__': <module 'builtins' (built-in)>, 
'func': <function func at 0x7fb1ce737b70>, 'i': 2, '__file__': '/usercode/file3.py', '__package__': None, '__doc__': None}
locals: {'j': 4}

locals和globals有個重要的區(qū)別:

#!/usr/bin/python
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)

---outputs---
{'x': 12345, 'i': 1, 'info': 'first'}
x= 12345
y= 9876

這是因為(待研究為什么這么設(shè)計):
1.locals 實際上沒有返回局部名字空間皱卓,它返回的是一個拷貝裹芝。所以對它進行改變對局部名字空間中的變量值并無影響。
2.globals 返回實際的全局名字空間娜汁,而不是一個拷貝嫂易。所以對 globals 所返回的 dictionary 的任何的改動都會直接影響到全局變量

此外,我們import時有2種方式:
1.from module import xxx
2.import module
在使用第一種時掐禁,會把被導入的module種方法和屬性放到當前的命名空間中怜械,所以可以直接使用方法和屬性進行訪問;而在第二種中傅事,模塊被導入缕允,保留了自身的命名空間,所以訪問其中的方法需要使用module.method()

參考:

  1. Python進階_關(guān)于命名空間與作用域(詳解)
  2. Python命名空間和作用域窺探
  3. Python Scopes and Namespaces
  4. 命名空間的本質(zhì)
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末蹭越,一起剝皮案震驚了整個濱河市障本,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌响鹃,老刑警劉巖驾霜,帶你破解...
    沈念sama閱讀 216,591評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異买置,居然都是意外死亡粪糙,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,448評論 3 392
  • 文/潘曉璐 我一進店門堕义,熙熙樓的掌柜王于貴愁眉苦臉地迎上來猜旬,“玉大人,你說我怎么就攤上這事倦卖∪鞑粒” “怎么了?”我有些...
    開封第一講書人閱讀 162,823評論 0 353
  • 文/不壞的土叔 我叫張陵怕膛,是天一觀的道長熟嫩。 經(jīng)常有香客問我,道長褐捻,這世上最難降的妖魔是什么掸茅? 我笑而不...
    開封第一講書人閱讀 58,204評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮柠逞,結(jié)果婚禮上昧狮,老公的妹妹穿的比我還像新娘。我一直安慰自己板壮,他們只是感情好逗鸣,可當我...
    茶點故事閱讀 67,228評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般撒璧。 火紅的嫁衣襯著肌膚如雪透葛。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,190評論 1 299
  • 那天卿樱,我揣著相機與錄音僚害,去河邊找鬼。 笑死繁调,一個胖子當著我的面吹牛萨蚕,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播涉馁,決...
    沈念sama閱讀 40,078評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼门岔,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起食呻,我...
    開封第一講書人閱讀 38,923評論 0 274
  • 序言:老撾萬榮一對情侶失蹤骄崩,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后晶乔,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,334評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,550評論 2 333
  • 正文 我和宋清朗相戀三年试和,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片纫普。...
    茶點故事閱讀 39,727評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡阅悍,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出昨稼,到底是詐尸還是另有隱情节视,我是刑警寧澤,帶...
    沈念sama閱讀 35,428評論 5 343
  • 正文 年R本政府宣布假栓,位于F島的核電站寻行,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏匾荆。R本人自食惡果不足惜拌蜘,卻給世界環(huán)境...
    茶點故事閱讀 41,022評論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望牙丽。 院中可真熱鬧简卧,春花似錦、人聲如沸烤芦。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,672評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至晓铆,卻和暖如春勺良,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背骄噪。 一陣腳步聲響...
    開封第一講書人閱讀 32,826評論 1 269
  • 我被黑心中介騙來泰國打工尚困, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人链蕊。 一個月前我還...
    沈念sama閱讀 47,734評論 2 368
  • 正文 我出身青樓事甜,卻偏偏與公主長得像,于是被迫代替她去往敵國和親滔韵。 傳聞我的和親對象是個殘疾皇子逻谦,可洞房花燭夜當晚...
    茶點故事閱讀 44,619評論 2 354

推薦閱讀更多精彩內(nèi)容