打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
浅谈Python命名空间和作用域

命名空间和作用域(Namespace and Scope),Namespace只是从名字到对象的一个映射(a mapping from name to objects)。大部分namespace都是按Python中的字典来实现的。有一些常见的namespace:built-in中的集合(abs() 函数等)、一个模块中的全局变量等。从某种意义上来说,一个对象(object)的所有属性(attribute)也构成了一个namespace。在程序执行期间,可能(其实是肯定)会有多个名空间同时存在。不同namespace的创建/销毁时间也不同。

此外,两个不同namespace中的两个相同名字的变量之间没有任何联系。

scope

有了namespace基础之后,让我们再来看看scope。Scope是Python程序的一块文本区域(textual region)。

在该文本区域中,对namespace是可以直接访问,而不需要通过属性来访问。

Scope是定义程序该如何搜索确切地“名字-对象”的名空间的层级关系。

(The “scope” in Python defines the “hirerchy level” in which we search namespaces for

certain “name-to-object” mappings.)

Tip

直接访问:对一个变量名的引用会在所有namespace中查找该变量,而不是通过属性访问。

属性访问:所有名字后加 . 的都认为是属性访问。

如 module_name.func_name ,需要指定 func_name 的名空间,属于属性访问。

而 abs(-1),abs 属于直接访问。

两者之间有什么联系呢?

Important

在Python中,scope是由namespace按特定的层级结构组合起来的。

scope一定是namespace,但namespace不一定是scope.

LEGB-rule

在一个Python程序运行中,至少有4个scopes是存在的。

直接访问一个变量可能在这四个namespace中逐一搜索。

Local(innermost)

包含局部变量。

比如一个函数/方法内部。

Enclosing

包含了非局部(non-local)也非全局(non-global)的变量。

比如两个嵌套函数,内层函数可能搜索外层函数的namespace,但该namespace对内层函数而言既非局部也非全局。

Global(next-to-last)

当前脚本的最外层。

比如当前模块的全局变量。

Built-in(outtermost)

Python __builtin__ 模块。

包含了内建的变量/关键字等。

那么,这么多的作用域,Python是按什么顺序搜索对应作用域的呢?

著名的”LEGB-rule”,即scope的搜索顺序:

Important

Local -> Enclosing -> Global -> Built-in

怎么个意思呢?

当有一个变量在 local 域中找不到时,Python会找上一层的作用域,即 enclosing 域(该域不一定存在)。enclosing 域还找不到的时候,再往上一层,搜索模块内的 global 域。最后,会在 built-in 域中搜索。对于最终没有搜索到时,Python会抛出一个 NameError 异常。

作用域可以嵌套。比如模块导入时。这也是为什么不推荐使用 from a_module import * 的原因,导入的变量可能被当前模块覆盖。

Assignment rule

看似python作用域到此为止已经很清晰了,让我们再看一段代码:

def outer():

a = 0

b = 1

def inner():

print a

print b

inner()

outer()

你觉得结果是什么呢?So easy是不是?

如果多加一句呢?

def outer():

a = 0

b = 1

def inner():

print a

print b

# b += 1        # A

b = 4           # B

inner()

outer()

结果又会是什么呢?

Traceback (most recent call last):

File "a.py", line 34, in

outer()

File "a.py", line 32, in outer

inner()

File "a.py", line 29, in inner

print b

UnboundLocalError: local variable 'b' referenced before assignment

是不是很奇怪?原因是这样的:Python解释器执行到 inner() 中的 print b 时,发现有个变量 b 在当前作用域(local)中无法找到该变量。它继续尝试把整块代码解释完。Bingo! 找到了。那么 b 是属于 inner() 作用域的。既然对变量 b 的赋值(声明)发生在 print 语句之后,print 语句执行时变量 b 是还未被声明的,于是抛出错误:变量在赋值前就被引用。

在这个例子中,只有A语句没有B语句也会导致同样的结果。

因为 b += 1 等同于 b = b + 1。

对于变量的作用域查找有了了解之后,还有两条很重要的规则:

赋值语句通常隐式地会创建一个局部(local)变量,即便该变量名已存在于赋值语句发生的上一层作用域中;如果没有 global 关键字声明变量,对一个变量的赋值总是认为该变量存在于最内层(innermost)的作用域中;也就是说在作用域内有没有发生赋值是不一样的。

  (特别声明:以上文章内容仅代表作者本人观点,不代表新浪看点观点或立场。如有关于作品内容、版权或其它问题请于作品发布后的30日内与新浪看点联系。)

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
Javascript深层原理探讨【3】
12步轻松搞定python装饰器
教小朋友学 Python -- 函数与Lambda表达式
初识 Python:全局、局部和非局部变量(带示例) | Linux 中国
python基础7(函数 Ⅱ)
【Python之路】特别篇
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服