python中的作用域與命名空間

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

這三個命名空間分別有各自的生命周期:
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關鍵字:

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

在python3.X版本中引入了關鍵字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

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

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

參考:

  1. Python進階_關于命名空間與作用域(詳解)
  2. Python命名空間和作用域窺探
  3. Python Scopes and Namespaces
  4. 命名空間的本質(zhì)
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容