命名空間namespace
定義
我對於命名空間的理解是,由變量名到對象的一個映射,相當於字典中的key對應一個values。所以在同一個環境中,不能有相同的key,但在不同的環境中,key的值是可以重複的。
namespace又可以分爲三類:
- 內建命名空間(Builtins):在啓動python解釋器時創建,我覺得是特殊的全局命名空間,因爲它相當於導入了builtins模塊
- 全局命名空間(Global):在導入模塊時創建
- 局部命名空間(Local):在調用函數時創建
- 內嵌函數命名空間(Enclosing):函數內嵌函數時的特殊局部命名空間
創建
由以上的定義可以知道,在執行一個py腳本的時候,命名空間的創建流程是:內建->全局->局部(前提是內部有函數的調用)
Python 3.7.0 (default, Jun 28 2018, 07:39:16)
[Clang 4.0.1 (tags/RELEASE_401/final)] :: Anaconda, Inc. on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> def func1():
... name = 1
... print('localspace:',locals())
... print('globalspace:',globals())
... def func2():
... print('before func1 local:',locals())
... print('before func1 global:',globals())
... ayu = name
... print('after func1 local:',locals()) #1
... print('after func1 global:',globals())
... func2() #2
... print('after func2 local:',locals())
... print('after func2 global:',globals())
...
>>> func1()
localspace: {'name': 1}
globalspace: {'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <class '_frozen_importlib.BuiltinImporter'>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, 'func1': <function func1 at 0x10384c598>}
before func1 local: {'name': 1}
before func1 global: {'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <class '_frozen_importlib.BuiltinImporter'>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, 'func1': <function func1 at 0x10384c598>}
after func1 local: {'name': 1, 'ayu': 1}
after func1 global: {'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <class '_frozen_importlib.BuiltinImporter'>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, 'func1': <function func1 at 0x10384c598>}
after func2 local: {'name': 1, 'func2': <function func1.<locals>.func2 at 0x103855378>}
after func2 global: {'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <class '_frozen_importlib.BuiltinImporter'>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, 'func1': <function func1 at 0x10384c598>}
>>> del(func1) #3
>>> locals()
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <class '_frozen_importlib.BuiltinImporter'>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>}
>>> globals()
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <class '_frozen_importlib.BuiltinImporter'>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>}
>>>
以上代碼在命令行中執行,#2中調用完func2之後,#1中的局部命名空間被刪除,執行#3之後,func1中的全局命名空間被刪除,而builtins命名空間需要在退出解釋器後纔會被回收
所以命名空間回收的順序是局部->全局->builtins
調用
在調用變量是,遵循LEGB的順序,即Local->Enclosing(前提是有內嵌函數)->Global->Builtins
>>> def func1():
... x = 1
... print(x)
... def func2():
... x += x
... print(x)
... func2()
...
>>> func1()
1
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 7, in func1
File "<stdin>", line 5, in func2
UnboundLocalError: local variable 'x' referenced before assignment
>>>
在執行func2時會報錯,因爲執行func2時,會在局部變量中創建x,然後從其局部變量中查找x,始終沒有到Enclosing中取。