命名空间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中取。

参考的博客

由一个例子到python的名字空间 详解python命名空间和作用域