一,namespace
-
namespace是名字到对象的映射,python里面的大部分命名空间由字典实现。如果有性能问题,会更改。
-
命名空间的举例
•存放内置函数的集合(abs()这种函数,和内建的异常)
•模块中的全局名称
•函数调用中的局部名称
•某种意义,对象的属性集合
不同命名空间的名称没得关系,比如两个模块里面都有show()函数,只要指明是哪个模块就行。
-
三种命名空间的区别
• 内置名称(built-in names), Python 语言内置的名称,比如函数名 abs、char 和异常名称 BaseException、Exception 等等。• 全局名称(global names),模块中定义的名称,记录了模块的变量,包括函数、类、其它导入的模块、模块级的变量和常量。
• 非局部和非全局之间得名称 nonlocal
• 局部名称(local names),函数中定义的名称,记录了函数的变量,包括函数的参数和局部定义的变量。(类中定义的也是)
命名空间查找顺序:(从小到大)
假设我们要使用变量 BITQIAN,则 Python 的查找顺序为:局部的命名空间去 -> 全局命名空间 -> 内置命名空间。
如果找不到变量 BITQIAN,它将放弃查找并引发一个 NameError 异常:
int = 0
def test_namespace():int = 1def inner_show():int = 2print(int)inner_show()test_namespace() # 2 localdef test_namesapce():int = 1def inner_show():print(int) # 1 nonlocalinner_show()def test_namespace():def inner_show():print(int) # 0 global inner_show()del int
def test_namespace():def inner_show():print(int) # class<int> built-ininner_show()
-
命名空间的生命周期
1,不同时刻创建的命名空间有不同的生命周期,包含内置名称的命名空间(builtins)是在python解释器启动时创建的,不会被删除。
2,模块的全局命名空间在模块定义被读入时创建,一般,解释器退出,消失。
3,被解释器的顶层调用执行的语句,从一个脚本文件读取或交互式地读取,被认为是 main 模块调用的一部分,因此它们拥有自己
的全局命名空间。
4,命名空间的生命周期取决于对象的作用域,如果对象执行完成,则该命名空间的生命周期就结束。因此,无法从外部命名空间访问内 部命名空间的对象。 -
函数的命名空间
在调用时创建,函数返回值后,或者异常后删除。但递归调用会有自己的命名空间。
在调用时创建,函数返回值后,或者异常后删除。但递归调用会有自己的命名空间。
二,作用域
1, 作用域被静态确定,但被动态使用。 在程序运行的任何时间,至少有三个命名空间可被直接访问的嵌套作用域:
• 最先搜索的最内部作用域包含局部名称。 比如一个函数/方法内部。 - local• 从最近的封闭作用域开始搜索的任何封闭函数的作用域包含非局部名称,也包括非全局名称。 - 嵌套函数 nonlocal、一个函数(或类) A 里面又包含了一个函数 B ,那么对于 B 中的名称来说 A 中的作用域就为 nonlocal。• 倒数第二个作用域包含当前模块的全局名称 - global比如当前模块的全局变量。• 最外面的作用域(最后搜索)是包含内置名称的命名空间 - 一定存在 built-in
2,四种作用域的举例
- 全局名称与局部名称
# var1 是全局名称
var1 = 0
def my_func():var2 = 1 # var2 是局部名称def my_innerfunc():var3 = 2 # var3 是内嵌局部名称
- 访问全局,局部名称,是两个分开的东西
global_var = 0 # 全局作用域def show():local_var = 'nonlocal scope' # 闭包函数外的函数中# print(inner_local_var) 无法访问def local_func():inner_local_var = 'local scope' # 局部作用域local_func()show()
- 内置作用域
# 内置作用域import builtinsprint(dir(builtins))
- 控制语句的作用域可以理解是全局的
'''♥,在python中只有函数,类,lambda,模块才会引入新的作用域,其它的代码块不会引入(if elif else while / for try/except/else/finally)'''>>> try:... a = 1... print(1/0)... except:... print('you\'re wrong!')... raise... finally:... print('a', a)...you're wrong!a 1Traceback (most recent call last):File "<stdin>", line 3, in <module>ZeroDivisionError: division by zero>>> a1
- nonlocal,非全局也非局部,只可在嵌套函数内访问
def update_nonlocal(): # 全局名称var = 1 # 局部名称def inner():nonlocal var # 存在非局部,非全局变量之间var = 100print(var) # 100inner()print(var) # 100
3,global和nonlocal的区别
- nonlocal的作用域只在嵌套函数中,而且在第一个嵌套函数中声明了名称,才可在第二个函数中声明这个变量为nonlocal
def test_nonlocal():x = 99print(x, id(x))def show_x():nonlocal x print(x, id(x))x = 999print(x, id(x))show_x()test_nonlocal()
'''
99 140705925728384
99 140705925728384
999 2145717490672
'''
- global 的名称在函数中可以读,但是不可写,除非你把这个函数中的名称也申明为global
num = 1
print('全局名称num ', num)
def update_num():global num # 声明全局名称num = 11update_num()
print('global 关键字后,', num)
'''
全局名称num 1
global 关键字后, 11
'''
最后,一张namespace和scope的图送上