命名空间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__': , '__spec__': None, '__annotations__': {}, '__builtins__': , 'func1': }
before func1 local: {'name': 1}
before func1 global: {'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': , '__spec__': None, '__annotations__': {}, '__builtins__': , 'func1': }
after func1 local: {'name': 1, 'ayu': 1}
after func1 global: {'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': , '__spec__': None, '__annotations__': {}, '__builtins__': , 'func1': }
after func2 local: {'name': 1, 'func2': .func2 at 0x103855378>}
after func2 global: {'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': , '__spec__': None, '__annotations__': {}, '__builtins__': , 'func1': }
>>> del(func1) #3
>>> locals()
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': , '__spec__': None, '__annotations__': {}, '__builtins__': }
>>> globals()
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': , '__spec__': None, '__annotations__': {}, '__builtins__': }
>>>
以上代码在命令行中执行,#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 "", line 1, in
File "", line 7, in func1
File "", line 5, in func2
UnboundLocalError: local variable 'x' referenced before assignment
>>>
在执行func2时会报错,因为执行func2时,会在局部变量中创建x,然后从其局部变量中查找x,始终没有到Enclosing中取。
参考的博客
由一个例子到python的名字空间
详解python命名空间和作用域