Python学习之路(44)——命名空间与作用域

命名空间NameSpace

我们知道想要使用模块中的函数,就需要导入模块(import),此时就需要考虑命名空间的问题,否则使用函数就会报错。

命名空间是从名字到对象的一个映射(a mapping from name to objects),按照字典来实现,键是变量名,值就是变量的值。

一些常见的命名空间包括,built-in中的集合(abs()函数等),一个模块中的全局变量等。

从某种意义上来说,一个对象(object)的所有属性(attribute)也构成了一个命名空间。

在程序执行期间,会有多个命名空间同时存在:

1、每个函数拥有自己的命名空间,叫做局部命名空间,记录了函数的变量,包含函数的参数和局部定义的变量等;

2、每个模块也有自己的命名空间,叫做全局命名空间,记录了模块的变量,包含函数、类、其他导入的模块、模块级的变量等;

3、然后就是内置命名空间,任何模块都可以访问,包含内置函数和异常等。

 

作用域scope

作用域是Python程序的一块文本区域(testual region),在该区域,对命名空间是可以直接访问的,而不需要通过属性来访问。

作用域就是定义程序应当如何搜索确切的“名字-对象”的命名空间的层级关系。

注意:

直接访问:对一个变量名的引用会在所有命名空间中查找该变量,而不是通过属性访问。(比如abs(-1),abs就属于直接访问)

属性访问:所有名字后加 “.” 的都认为是属性访问。(比如module.fuction,需要知道function的命名空间,属性属性访问)

 

二者联系

在Python中,作用域是由命名空间按照特定的层级结构组合起来的。

因此,作用域一定是命名空间,但命名空间不一定是作用域。

 

LEGB-rule

在一个Python程序运行时,至少有4个作用域是存在的,直接访问一个变量可能在这些命名空间中逐一搜索。

Local(innermost):包含局部变量,比如一个函数/方法内部。

Enclosing:包含了非局部(non-local)也非全局(non-global)的变量。比如两个嵌套函数,内层函数可能搜索外层函数的命名空间,但该命名空间对内层函数而言,既非局部也非全局。

Global(next-to-last):当前脚本的最外层,比如当前模块的全局变量。

Built-in(outtermost):Python的__builtin__模块,包含了内建的变量/关键字等。

当有一个变量在Local域中找不到时,Python会在上一层Enclosing域(不一定存在)中搜索,如果找不到,则再往上一层,搜索模块内的Global域,如果还找不到,最后会在Build-in域中搜索。最终没有搜索到的话,Python会抛出NameError异常。

 

有两个例子:

示例1

def outer():
    a = 0
    b = 1

    def inner():
        print(a)
        print(b)

    inner()

outer()

##########执行结果##########
C:\Python35\python3.exe D:/Project/Python/Pro_py3/test.py
0
1

示例2

def outer():
    a = 0
    b = 1

    def inner():
        print(a)
        print(b)

        b = 4

    inner()

outer()

##########执行结果##########
C:\Python35\python3.exe D:/Project/Python/Pro_py3/test.py
0
Traceback (most recent call last):
  File "D:/Project/Python/Pro_py3/test.py", line 13, in <module>
    outer()
  File "D:/Project/Python/Pro_py3/test.py", line 11, in outer
    inner()
  File "D:/Project/Python/Pro_py3/test.py", line 7, in inner
    print(b)
UnboundLocalError: local variable 'b' referenced before assignment

可以思考一下,为什么第一个示例正常运行,第二个示例抛出异常。

这里有2条规则很重要:

1、赋值语句通常会隐式地创建一个local变量,即便该变量名已存在赋值语句发生的上一层作用域中;

2、如果没有global关键字声明变量,对一个变量的赋值总是认为该变量存在于最内层(innermost)的作用域中。

 

posted on 2018-03-23 11:23  nicolas_Z  阅读(186)  评论(0)    收藏  举报

导航