python命名空间和作用域

发布时间:2022-04-21 09:52:07 人气:45 作者:多测师

  命名空间表示标识符(identifier)的可见范围,当前命名空间主要是通过 Python 字典实现的,不过通常不关心具体的实现方式(除非出于性能考虑),以后也有可能会改变其实现方式。有一些命名空间的例子:内置命名(像 abs() 这样的函数,以及内置异常名)集,模块中的全局命名,函数调用中的局部命名。某种意义上讲对象的属性集也是一个命名空间。有几个点需要注意下:

  第一:不同命名空间中的命名没有任何联系,例如两个不同的模块可能都会定义一个名为 maximize的函数而不会发生混淆--用户必须以模块名为前缀来引用它们。

  第二:不同的命名空间在不同的时刻创建,有不同的生存期。包含内置命名的命名空间在 Python 解释器启动时创建,会一直保留,不被删除。模块的全局命名空间在模块定义被读入时创建,通常,模块命名空间也会一直保存到解释器退出。由解释器在最高层调用执行的语句,不管它是从脚本文件中读入还是来自交互式输入,都是 __main__ 模块的一部分,所以它们也拥有自己的命名空间。(内置命名也同样被包含在一个模块中,它被称作 __builtin__ 。)

  第三:当调用函数时,就会为它创建一个局部命名空间,并且在函数返回或抛出一个并没有在函数内部处理的异常时被删除。 (实际上,用遗忘来形容到底发生了什么更为贴切。) 当然,每个递归调用都有自己的局部命名空间。

  作用域是定义程序该如何搜索确切地“名字-对象”的名空间的层级关系。是一个 Python 程序可以直接访问命名空间的正文区域。 意思是一个对名称的错误引用会尝试在命名空间内查找。尽管作用域是静态定义,在使用时他们都是动态的。每次执行时,至少有四个命名空间可以直接访问的作用域嵌套在一起:

  第一:innermost scope ,包含局部命名的使用域在最里面,首先被搜索;

python命名空间和作用域

  第二:enclosing scope ,中层的作用域,是内层嵌套作用域搜索起点,包含非局部,但是也非全局的命名

  第三:Global scope ,包含当前模块的全局命名

  第四:Built-in scope ,包含内置命名的命名空间。

  so,这么多的作用域,Python是按什么顺序搜索对应作用域的呢?著名的”LEGB-rule”,即scope的搜索顺序:Local -> Enclosing -> Global -> Built-in;当有一个变量在 local 域中找不到时,Python会找上一层的作用域,即 enclosing 域(该域不一定存在)。enclosing 域还找不到的时候,再往上一层,搜索模块内的 global 域。最后,会在 built-in 域中搜索。对于最终没有搜索到时,Python会抛出一个 NameError 异常。作用域可以嵌套。比如模块导入时。这也是为什么不推荐使用 from a_module import * 的原因,导入的变量可能被当前模块覆盖。下面是一个例子:

  def outer():

  a = 0

  b = 1

  def inner():

  print a

  print b

  b = 4

  inner()

  if __name__=="__main__": outer()

  Traceback (most recent call last):

  File "E:/PycharmProjects/CodeStatisticsTools/test_namespaces.py", line 37, in

  outer()

  File "E:/PycharmProjects/CodeStatisticsTools/test_namespaces.py", line 18, in outer

  inner()

  File "E:/PycharmProjects/CodeStatisticsTools/test_namespaces.py", line 15, in inner

  print b

  UnboundLocalError: local variable 'b' referenced before assignment

  如果去掉b = 4 就能正常运行,这是为啥呢?在没有b=4这行代码时,Python解释器执行到 inner() 中的 print b 时,发现有个变量 b 在当前作用域(local)中无法找到变量b,于是尝试从enclosing scope中查找,找到后就能正常打印了。加上这行代码后,在当前作用域找到了b ,但是变量 b 的赋值发生在 print 语句之后,于是抛出错误:变量在赋值前就被引用。赋值语句通常隐式地会创建一个局部(local)变量,即便该变量名已存在于赋值语句发生的上一层作用域中

  以上内容为大家介绍了python命名空间和作用域,希望对大家有所帮助,如果想要了解更多Python相关知识,请关注多测师。https://www.e70w.com/xwzx/


返回列表
在线客服
联系方式

热线电话

17727591462

上班时间

周一到周五

二维码
线