Python在这方面设计了PyFrameObject这个结构(对应于龙书中的“活动记录”)来维护运行时环境,并采用了“访问链”的思想(龙书中介绍了“访问链”和“显示表”)来解决不同作用域间变量的访问问题。
不过在PyFrameObject中维护了3个成员,用来指向最经常使用的3个符号表,内置符号表、全局符号表、局部符号表:
PyObject*f_builtins;/*builtin symbol table (PyDictObject) */
PyObject*f_globals;/*global symbol table (PyDictObject) */
PyObject*f_locals;/*local symbol table (any mapping) */
这样可以避免在访问全局变量、内建变量时还要通过“访问链”上的回溯来搜索。
PyFrameObject通过如下成员来维护“访问链”(或者称“符号表链”、“名字空间链”):
struct_frame*f_back;/*previous frame, or NULL */
关于Python的作用域,有一些规则。
最内嵌套作用域规则:由一个赋值语句引进的名字在这个赋值语句所在的作用域里是可见(起作用)的,而且在其内部嵌套的每个作用域里也可见,除非它被嵌套于内部的,引进同样名字的另一条赋值语句所遮蔽/覆盖。
LEGB:符号表的搜索顺序是Local -> Enclosing Function -> Global -> Built-in
一个比较常见而且经典的案例是UnboundLocalError,见如下代码:
x = 10
def foo():
print(x)
x += 1
foo()
这一段代码会出现如下错误:
UnboundLocalError: local variable 'x' referenced before assignment
这个问题可以用下面两段话来解答:
This is because when you make an assignment to a variable in a scope, that variable becomes local to that scope and shadows any similarly named variable in the outer scope. Since the last statement in foo assigns a new valuetox, the compiler recognizes it as a local variable. Consequently when the earlierprintxattemptsto print the uninitialized local variable and an error results.
URL:http://docs.python.org/faq/programming.html#why-am-i-getting-an-unboundlocalerror-when-the-variable-has-a-value
Otherwise, all variables found outside of the innermost scope areread-only(an attempt to write to such a variable will simply create anewlocalvariable in the innermost scope, leaving the identically named outer variable unchanged).
URL:http://docs.python.org/tutorial/classes.html#python-scopes-and-namespaces
第二个URL,即官方文档也说明了LEGB规则:
the innermost scope, which is searched first, contains the local names
the scopes of any enclosing functions, which are searched starting with the nearest enclosing scope, contains non-local, but also non-global names
the next-to-last scope contains the current module’s global names
the outermost scope (searched last) is the namespace containing built-in names