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()
參考: