Python 作用域和命名空间
Posted Mr-chen
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python 作用域和命名空间相关的知识,希望对你有一定的参考价值。
Python Scopes and Namespaces
A namespace is a mapping from names to objects.
命名空间是一个从名字到对象的映射(指向,明确的路径)。
Most namespaces are currently implemented as Python dictionaries。
大部分都是由字典dict(其他语言也称为hash)实现。
例子:
the set of built-in names 。放置内置函数的集合。模块中的全局名称;函数调用中的局部名称。 从某种意义上说,对象的属性集合也是一种命名空间的形式。
namespaces is that there is absolutely no relation between names in different namespaces.
不同命名空间的名字之间没有关系,即相同的名字,在不同的命名空间是没有任何关系的。
生存周期lifetimes。
Namespaces are created at different moments and have different lifetimes.
例如:
模块的全局命名空间在模块定义被读入时创建,并持续到解释器退出。内置名称实际上也存在于一个模块builtins中。
函数的local namespace在函数被调用时创建,在函数返回或抛出一个不在函数内处理的?时被删除。
作用域
A scope is a textual region of a Python program where a namespace is directly accessible.
作用域是一个代码区域,是一个命名空间可以直接引用的区域。
我的理解:
调用函数形成的函数内部的命名空间(映射/指针/路径/hash),在函数内部可以使用函数代码外定义的名字,由此得到名字对应的对象。那么函数代码外部的代码区域,就是一个可被这个函数直接使用的作用域。
??函数的外部作用域是在函数定义时,对应的位置,而不是调用时对应的位置。
??:参考了这篇文章:https://www.linuxidc.com/Linux/2018-12/155918.htm
命名空间的查找顺序:
Local:首先搜索,包含局部名字的最内层(innermost)作用域,如函数/方法/类的内部局部作用域;
Enclosing:根据嵌套层次从内到外搜索,包含非局部(nonlocal)非全局(nonglobal)名字的任意封闭函数的作用域。如两个嵌套的函数,内层函数的作用域是局部作用域,外层函数作用域就是内层函数的 Enclosing作用域;
Global:倒数第二次被搜索,包含当前模块全局名字的作用域;
Built-in:最后被搜索,包含内建名字的最外层作用域。
Python按照以上LEGB的顺序依次在四个作用域搜索名字,没有搜索到时,Python抛出NameError异常。
用一个类比来理解命名空间与作用域: 四种作用域相当于我们生活中的国家(Built-in)、省(Global)、市(Enclosing)、县(Local),命名空间相当于公务员花名册,记录着哪个职位是哪个人。国家级公务员服务于全国 民众(全国老百姓都可以喊他办事),省级公务员只服务于本身民众(国家层面的人或者其他省的人我不管),市(Enclosing)、县(Local)也是一个道理。当我们要找某一类领导(例如想找 个警察帮我打架)时(要访问某个名称),如果我是在县(Local)里头,优先在县里的领导花名册中找(优先在自己作用域的命名空间中找),县里花名册中没警察没有就去市里的花名册找(往 上一层作用域命名空间找),知道找到国家级都还没找到,那就会报错。如果省级民众想找个警察帮忙大家,不会找市里或者县里的,只会找自己省里的(其它省都不行),或者找国家级的。国家、 省、市、县肯定一直都在那里,可不会移动(作用域是静态的);领导可以换届,任期移到就换人(命名空间是动态的,每次调用函数都会新的命名空间,函数执行
glocal与nonlocal的区别
第一,两者的功能不同。
global关键字修饰变量后标识该变量是全局变量,对该变量进行修改就是修改全局变量,而nonlocal关键字修饰变量后标识该变量是上一级函数中的局部变量,如果上一级函数中不存在该局部变量,nonlocal位置会发生错误。
def f1(): # i = 1 def f2(): nonlocal i print(i) i = 2 f2() print(i) f1() # SyntaxError: no binding for nonlocal ‘i‘ found
第二,两者使用的范围不同。
- global关键字可以用在任何地方,包括最上层函数中和嵌套函数中,即使之前未定义该变量,global修饰后也可以直接使用。
- nonlocal关键字只能用于嵌套函数中,并且外层函数中定义了相应的局部变量,否则会发生错误。
i = 0 def f1(): i = 1 def f2(): global i #重新绑定 print("global", i) i = 2 f2() print("local",i) f1() # 输出: # global 0 # local 1
几个例子:
i = 1 def f1(): print(i) def f2(): i = 2 f1() f2() print(i) #输出 #1 #1
解释:这个例子,说明了函数的外部作用域,是函数定义时的外部代码。
if True: i = 1 print(i) # 可以正常输出i的值1,不会报错
解释:这说明了if语句不产生新的作用域, 只有函数/类才会产生新作用域。
for i in range(10): pass print(i) #输出结果是9,而不是NameError
解释: 无关作用域,i被声明,并被赋值。
def test(): print(i) i= 2 i = 0 test()
解释:会报告错误,UnboundLocalError: local variable ‘i‘ referenced before assignment。i已经被占用了。所以不能再被重新声明。
class A(object): a = 2 def fun(self): print(a) new_class = A() new_class.fun() #NameError: name ‘a‘ is not defined
解释:还不理解。fun函数的外部作用领中,没有a。
以上是关于Python 作用域和命名空间的主要内容,如果未能解决你的问题,请参考以下文章