#!/usr/bin/env python
# encoding: utf-8
deffunc1
(): x = 1
print globals()
print
'before func1:', locals()
deffunc2
(): a = 1
print
'before fun2:', locals()
a += x
print
'after fun2:', locals()
func2()
print
'after func1:', locals()
print globals()
if __name__ == '__main__':
func1()
###before func1:
before fun2:
after fun2:
after func1:
#!/usr/bin/env python
# encoding: utf-8
deffunc1
(): x = 1
print
'before func1:', locals()
deffunc2
():print
'before fun2:', locals()
x += x #就是這裡使用x其餘地方不變
print
'after fun2:', locals()
func2()
print
'after func1:', locals()
if __name__ == '__main__':
func1()
###before func1:
before fun2:
traceback (most recent call last):
file "c:\desktop\b.py", line 21, in
func1()
file "c:\desktop\b.py", line 16, in func1
func2()
file "c:\desktop\b.py", line 13, in func2
x += x
unboundlocalerror: local variable 'x' referenced before assignment
python裡面有很多名字空間,每個地方都有自己的名字空間,互不干擾,不同空間中的兩個相同名字的變數之間沒有任何聯絡一般有4種: legb四種
- locals: 函式內部的名字空間,一般包括函式的區域性變數以及形式引數
- enclosing function: 在巢狀函式中外部函式的名字空間, 對fun2來說, fun1的名字空間就是。
- globals: 當前的模組空間,模組就是一些py檔案。也就是說,globals()類似全域性變數。
-builtins: 內建模組空間, 也就是內建變數或者內建函式的名字空間。
當程式引用某個變數的名字時,就會從當前名字空間開始搜尋。搜尋順序規則便是: legb.一層一層的查詢,找到了之後,便停止搜尋,如果最後沒有找到,則丟擲在nameerror的異常。這裡暫時先不討論賦值操作。 比如例1中的a = x + 1 這行**,需要引用x, 則按照legb的順序查詢,locals()也就是func2的名字空間沒有,進而開始e,也就是func1,裡面有,找到了,停止搜尋,還有後續工作,就是把x也加到自己的名字空間,這也是為什麼fun2的名字空間裡面也有x的原因。
#!/usr/bin/env python
# encoding: utf-8
import copy
from copy import deepcopy
deffunc
(): x = 123
print
'func locals:',locals()
s = 'hello world'
if __name__ == '__main__':
func()
print
'globals:', globals()
###func locals:
globals:
從輸出結果可以看出globals()包含了定義的函式,變數等。對於』deepcopy』: 可以看出deepcopy已經被匯入到自己的名字空間了,而不是在copy裡面。而匯入的import copy則還保留著自身的名字空間。因此要訪問copy的方法,就需要使用copy.function了。
這也就是為什麼推薦使用import module的原因,因為from a import b這樣會把b引入自身的名字空間,容易發生覆蓋或者說汙染。
每個名字空間都有自己的生存週期,如下:看著沒有問題,但是有很多地方需要考慮。比如名字空間都是在**編譯時期確定的,而不是執行期間。這個也就可以解釋為什麼在例1中,before func2:的locals()裡面包含了x: 1 這一項。再看下面這個,-builtins: 在python直譯器啟動的時候,便已經建立,直到退出
- globals: 在模組定義被讀入時建立,通常也一直儲存到直譯器退出。
- locals : 在函式呼叫時建立, 直到函式返回,或者丟擲異常之後,銷毀。
- 另外遞迴函式每一次均有自己的名字空間。
def
func
():if
false:
x = 10
#該語句永遠不執行
print x
###traceback (most recent call last):
file "c:\desktop\b.py", line 6, in
func()
file "c:\desktop\b.py", line 4, in func
print x
unboundlocalerror: local variable 'x' referenced before assignment
雖然x = 10永遠不會執行,但是在執行之前的編譯階段,就會把x作為locals變數,但是後面編譯到print的時候,發現沒有賦值,因此直接丟擲異常,locals()裡面便不會有x。這個就跟例子2中,before func2裡面沒有x是乙個道理。現在再看例子2, 就清晰多了, x += x 編譯到這裡時,發現了賦值語句,於是準備把x新加入最內層名字空間也就是func2中,即使上層函式已經存在了; 但是賦值的時候,又要用到x的值, 然後就會報錯:
這樣看起來好像就是 內部函式只可以讀取外部函式的變數,而不能做修改,其實本質還是因為賦值涉及到了新建locals()的名字。 在稍微改一點:
!/usr/bin/env python
# encoding: utf-8
deffunc1
(): x = [1,2]
print
'before func1:', locals()
deffunc2
():print
'before fun2:', locals()
x[0] += x[0] #就是這裡使用x[0]其餘地方不變
print
'after fun2:', locals()
func2()
print
'after func1:', locals()
if __name__ == '__main__':
func1()
這個例子其實也給了我們乙個啟發,我們知道內部函式無法直接修改外部函式的變數值,如例2,如果借助list的話, 就可以了吧!比如把想要修改的變數塞到乙個list裡面,然後在內部函式裡面做改變!當然python3.x裡面有了nonlocal關鍵字,直接宣告一下就可以修改了。 作用域與生存期
1.作用域 作用域指識別符號能夠被使用的範圍 只有在作用域內識別符號才可以被使用。在此階段針對編譯和鏈結過程。1 函式中定義的識別符號,包括形參和函式體中定義的區域性變數,作用域都在函式內,也稱作函式域。2 檔案作用域也稱全域性作用域。定義在所有函式之外的識別符號,具有檔案作用域,作用域為從定義處到...
08 作用域和生存期
2019獨角獸企業重金招聘python工程師標準 變數的作用域 scope 變數起作用或有效的 範圍,空間。變數的生存期 life time 變數存在的時間範圍,時間。1 根據變數的作用域將變數分為全域性變數和區域性變數 全域性變數儲存在靜態資料區,區域性變數在堆疊中。全域性變數 global va...
命名空間作用域
作用域 命名空間所能夠作用的範圍 內建命名空間 程式在任何階段任何位置均可以使用 全域性有效 全域性命名空間 程式在任何階段任何位置均可以使用 全域性有效 區域性命名空間 一般情況下只在各自的區域性命名空間有效 global 在區域性命名空間內更改全域性命名空間變數,使用關鍵字生命。在變數是不可變型...