您所在的位置: 首页>>读书频道>>设计开发>>其它开发>>

8.2.3.3 global 表达式

http://book.51cto.com  2008-07-23 16:20  陈儒著  电子工业出版社  我要评论(0)
  • 摘要:《Python源码剖析--深度探索动态语言核心技术》第8章Python 虚拟机框架,从这一章开始,我们将切入Python 字节码虚拟机,深入剖析Python 字节码虚拟机的运行机理,本小节为大家介绍的是global 表达式。
  • 标签:Python  源码剖析  global  动态语言  C程序员

8.2.3.3 global 表达式

初学Python 时,由于大家不清楚Python 的作用域规则,所以会对一些出错的情况百思不得其解。比如下面的例子:

 a = 1
def g():
print a
def f():
print a //[1]
a = 2 //[2]
print a
g()
f()

运行的结果会抛出异常,显示代码清单8-2 的[1]处有错,异常的信息为“localvariable 'a' referenced before assignment”。什么?a 没有赋值?不对呀,在module定义的作用域内明明已经建立了“a = 1”这个约束,按照LEGB 规则,这个输出结果应该是1 才对,而且在调用f 之前我们调用了函数g,g 可是已经老老实实地输出了结果,怎么到了函数f 里,同样的代码,就说没有赋值了呢?

理解这个错误的关键在于深刻理解最内嵌套作用域规则,这个规则的第一句话就是这个奇怪问题的症结所在。“由一个赋值语句引进的名字在这个赋值语句所在的作用域里是可见(起作用)的”,这句话的意思对应到这里,就是说虽然“a = 2”这个约束是在“printa”之后建立的,但是由于它们在同一个作用域内,所以在代码清单8-2 的[1]处,“a = 2”这个约束的名字a 就是可见的,按照LEGB 规则,在local 名字空间中就能找到名字a,所以使用的是local 名字空间中的a 所对应的对象。但是很不幸的是,虽然名字a 在[1]处已经可见了,但是要到[2]处对这个名字的赋值动作才会发生,a 才会引用一个有效的对象,所以在[1]处当然应该抛出一个“referenced before assignment”的异常。

更为有趣的东西隐藏在编译之后的字节码中,我们可以看看上面的代码反汇编的结果,如下所示:

 a = 1
def g():
print a
#0 LOAD_GLOBAL 0 (a)
#3 PRINT_ITEM
#4 PRINT_NEWLINE
def f():
print a
#0 LOAD_FAST 0 (a)
#3 PRINT_ITEM
#4 PRINT_NEWLINE
a = 2

对于相同的“print a”,Python 竟然编译出了不同的字节码指令,在函数g 中,名字引用对应的字节码指令是LOAD_GLOBAL,意思是要在global 名字空间中查找名字;而在函数f 中,名字引用对应的字节码指令为LOAD_FAST,这条指令是指在local 名字空间中查找名字,也就是说Python 在编译时就已经知道名字究竟藏身于何处。这正说明了Python 采用的是静态作用域规则,仅仅根据程序正文就能确定名字引用策略。同时,这个现象又一次地说明了最内嵌套作用域规则是指导Python 实现(这一次是编译器的实现)的“道”。

上面的例子表明,一旦作用域中有了对于某个名字的赋值操作,这个名字就会在作用域中可见,就会出现在local 名字空间中。换句话说,就遮蔽了外围作用域的相同的名字。但是有的时候,我们就是想在函数f 中输出外围作用域的名字a,同时还要对a 进行赋值,但是这个赋值操作在我们的设想中应该改变外围作用域中的名字a 对应的对象,Python 精心地为我们准备了global 关键字。当一个作用域中出现了global 语句时,就意味着我们强制命令Python 对某个名字的引用只参考global 名字空间,而不用再去管LEGB 规则。看了下面两个例子,你就会对glboal 语句了如指掌了:

 a = 1
def f():
global a
print a //输出结果:1
a = 2
f()
print a //输出结果:2

 a = 1
def f():
a = 2
def g():
global a
print a //输出结果:1
a += 1
return g
g = f()
g()
print a //输出结果:2
【责任编辑:夏书 TEL:(010)68476606】

回书目   上一节   下一节
Python实用开发指南
深入Vista应用程序开发
Ruby on Rails 社区网站开发
ASP.NET从入门到精通
Java完全自学宝典
 
 验证码: (点击刷新验证码)   匿名发表
  • Visual C++ 完全自学宝典

  • 作者:强锋科技,朱洪波
  • Visual C++ 6.0是微软公司为程序人员提供的Visual Studio 6.0工具套件中的重要组成部分。本书由浅入深地介绍使用Visual C++ 6.0..
Copyright©2005-2008 51CTO.COM 版权所有