Namespace(只)是 从名字到对象的一个映射(a mapping from name to objects) 。大部分namespace都是按Python中的字典来实现的。有一些常见的namespace:built-in中的集合( abs() 函数等)、一个模块中的全局变量等。
从某种意义上来说,一个对象(object)的所有属性(attribute)也构成了一个namespace。在程序执行期间,可能(其实是肯定)会有多个名空间同时存在。不同namespace的创建/销毁时间也不同。
此外,两个不同namespace中的两个相同名字的变量之间没有任何联系。
有了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.
在一个Python程序运行中,至少有4个scopes是存在的。
直接访问一个变量可能在这四个namespace中逐一搜索。
那么,这么多的作用域,Python是按什么顺序搜索对应作用域的呢?
著名的”LEGB-rule”,即scope的搜索顺序:
Important
Local -> Enclosing -> Global -> Built-in
怎么个意思呢?
当有一个变量在 local 域中找不到时,Python会找上一层的作用域,即 enclosing 域(该域不一定存在)。enclosing 域还找不到的时候,再往上一层,搜索模块内的 global 域。最后,会在 built-in 域中搜索。对于最终没有搜索到时,Python会抛出一个 NameError 异常。
作用域可以嵌套。比如模块导入时。
这也是为什么不推荐使用 from a_module import * 的原因,导入的变量可能被当前模块覆盖。
看似python作用域到此为止已经很清晰了,让我们再看一段代码:
| 1234567891011 | def outer(): a = 0 b = 1 def inner(): print a print b inner() outer() |
你觉得结果是什么呢?So easy是不是?
| 123 | cipher<a href=\”http://www.jobbole.com/members/rachel\”>@Rachel</a> ~/Development/Workspace/test_Python $ python2 a.py01 |
如果多加一句呢?
| 123456789101112131415 | def outer(): a = 0 b = 1 def inner(): print a print b # b += 1 # A b = 4 # B inner() outer() |
结果又会是什么呢?
| 12345678910 | cipher<a href=\”http://www.jobbole.com/members/rachel\”>@Rachel</a> ~/Development/Workspace/test_Python $ python2 a.py0Traceback (most recent call last): File \”a.py\”, line 34, in <module> outer() File \”a.py\”, line 32, in outer inner() File \”a.py\”, line 29, in inner print bUnboundLocalError: 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。
对于变量的作用域查找有了了解之后,还有两条很重要的规则:
Important
也就是说在作用域内有没有发生赋值是不一样的。
但是,在这点上,Python 2和Python 3又有不同, Python access non-local variable:
Python’s scoping rules indicate that a function defines a new scope level,
and a name is bound to a value in only one scope level – it is statically scoped.
…
In Python 2.x, it is not possible to modify a non-local variable;
1) you have either read-only access to a global or non-local variable,
2) or read-write access to a global variable by using the global statement,
3) or read-write access to a local variable (by default).
In Python 3.x, the nonlocal statement has been introduced with a similar effect
to global, but for an intermediate scope.
为什么讲到作用域要说到 for 循环呢?难道!@#$%^&*()???
对于大部分语言(比如 C 语言)而言, for-loop 会引入一个新的作用域。
但Python有点一样却又不太一样。
让我们先来看个例子:
| 12345678910111213141516171819 | f=\”http://blog.cipherc.com/2015/04/25/python_namespace_and_scope/#namespace-and-scope\”>
namespaceNamespace(只)是 从名字到对象的一个映射(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是定义程序该如何搜索确切地“名字-对象”的名空间的层级关系。 Tip 直接访问:对一个变量名的引用会在所有namespace中查找该变量,而不是通过属性访问。 属性访问:所有名字后加 . 的都认为是属性访问。 如 module_name.func_name ,需要指定 func_name 的名空间,属于属性访问。 两者之间有什么联系呢?Important 在Python中,scope是由namespace按特定的层级结构组合起来的。 scope一定是namespace,但namespace不一定是scope. LEGB-rule在一个Python程序运行中,至少有4个scopes是存在的。 直接访问一个变量可能在这四个namespace中逐一搜索。
那么,这么多的作用域,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作用域到此为止已经很清晰了,让我们再看一段代码:
你觉得结果是什么呢?So easy是不是?
如果多加一句呢?
结果又会是什么呢?
是不是很奇怪? 原因是这样的: Python解释器执行到 inner() 中的 print b 时,发现有个变量 b 在当前作用域(local)中 Bingo! 找到了。那么 b 是属于 inner() 作用域的。 在这个例子中,只有A语句没有B语句也会导致同样的结果。 对于变量的作用域查找有了了解之后,还有两条很重要的规则: Important
也就是说在作用域内有没有发生赋值是不一样的。 但是,在这点上,Python 2和Python 3又有不同, Python access non-local variable: Python’s scoping rules indicate that a function defines a new scope level, … In Python 2.x, it is not possible to modify a non-local variable; In Python 3.x, the nonlocal statement has been introduced with a similar effect for 循环为什么讲到作用域要说到 for 循环呢?难道!@#$%^&*()??? 对于大部分语言(比如 C 语言)而言, for-loop 会引入一个新的作用域。 让我们先来看个例子:
|