- 译者序
- 前言
- 第1章 问答环节
- 第2章 Python 如何运行程序
- 第3章 如何运行程序
- 第4章 介绍 Python 对象类型
- 第5章 数字
- 第6章 动态类型简介
- 第7章 字符串
- 第8章 列表与字典
- 第9章 元组、文件及其他
- 第10章 Python 语句简介
- 第11章 赋值、表达式和打印
- 第12章 if 测试和语法规则
- 第13章 while 和 for 循环
- 第14章 迭代器和解析,第一部分
- 第15章 文档
- 第16章 函数基础
- 第17章 作用域
- 第18章 参数
- 第19章 函数的高级话题
- 第20章 迭代和解析,第二部分
- 第21章 模块:宏伟蓝图
- 第22章 模块代码编写基础
- 第23章 模块包
- 第24章 高级模块话题
- 第25章 OOP:宏伟蓝图
- 第27章 更多实例
- 第28章 类代码编写细节
- 第29章 运算符重载
- 第30章 类的设计
- 第31章 类的高级主题
- 第32章 异常基础
- 第34章 异常对象
- 第35章 异常的设计
- 第36章 Unicode 和字节字符串
- 字符串基础知识
- Python 的字符串类型
- 文本和二进制文件
- Python 3.0 中的字符串应用
- 转换
- 编码 Unicode 字符串
- 编码非ASCII文本
- 编码和解码非ASCII文本
- 其他 Unicode 编码技术
- 转换编码
- 在 Python 2.6 中编码 Unicode 字符串
- 源文件字符集编码声明
- 使用 Python 3.0 Bytes 对象
- 序列操作
- 创建 bytes 对象的其他方式
- 混合字符串类型
- 使用 Python 3.0(和 Python 2.6)bytearray 对象
- 使用文本文件和二进制文件
- Python 3.0 中的文本和二进制模式
- 类型和内容错误匹配
- 使用 Unicode 文件
- 在 Python 3.0 中处理 BOM
- Python 2.6 中的 Unicode 文件
- Python 3.0 中其他字符串工具的变化
- Struct二进制数据模块
- pickle对象序列化模块
- XML解析工具
- 本章小结
- 本章习题
- 习题解答
- 第37章 管理属性
- 第38章 装饰器
- 第39章 元类
- 附录A 安装和配置
- 附录B 各部分练习题的解答
- 作者介绍
- 封面介绍
global 语句
我们已经在前边讲过了全局变量名。这里只是作一个总结。
·全局变量是位于模块文件内部的顶层的变量名。
·全局变量如果是在函数内被赋值的话,必须经过声明。
·全局变量名在函数的内部不经过声明也可以被引用。
换句话说,global允许我们修改一个模块文件的顶层的一个def之外的名称。正如我们将在随后看到的,nonlocal语句几乎是相同的,但它应用于嵌套的def的本地作用域内的名称,而不是嵌套的模块中的名称。
global语句包含了关键字global,其后跟着一个或多个由逗号分开的变量名。当在函数主体被赋值或引用时,所有列出来的变量名将被映射到整个模块的作用域内。例如:
这个例子中我们增加了一个global声明,以便在def之内的X能够引用在def之外的X,这次它们有相同的值。这里有一个global使用的例子:
这里,x、y和z都是all_global函数内的全局变量。y和z是全局变量,因为它们不是在函数内赋值的;x是全局变量,因为它通过global语句使自己明确地映射到了模块的作用域。如果不使用global语句的话,x将会由于赋值而被认为是本地变量。
注意:y和z并没有进行global声明。Python的LEGB查找法则将会自动从模块中找到它们。此外,注意x在函数运行前可能并不存在。如果这样的话,函数内的赋值语句将自动在模块中创建x这个变量。
最小化全局变量
在默认情况下,函数内部注册的变量名是本地变量,所以如果希望在函数外部对变量进行改变,必须编写额外的代码(global语句)。这是有意而为的。这似乎已成为Python中的一种惯例,如果想做些“错误”的事情,就得多编写代码。尽管有些时候global语句是有用的,然而在def内部赋值的变量名默认为本地变量,通常这都是最好的约定。将其改为全局变量会引发一些软件工程问题:由于变量的值取决于函数调用的顺序,而函数自身是任意顺序进行排列的,导致了程序调试起来变得很困难。
作为例子,思考一下这个模块文件。
现在,假设你的任务就是修改或重用这个模块文件。这里X的值将会是什么?确切地说,如果不确定引用的时间,这个问题就是毫无意义的。X的值与时间相关联,因为它的值取决于哪个函数是最后进行调用的(有时我们是无法单从这个文件就能说明白的)。
实际的结果就是,为了理解这个代码,你必须去跟踪整个程序的控制流程。此外,如果重用或修改了代码,你必须随时记住整个程序。在这种情况下,如果使用这两个函数中的一个的话,必须要确保没有在使用另一个函数。它们通过全局变量而变得具有相关性(也就是说,是耦合在一起的)。这就是使用全局变量的问题:不像那些依赖于本地变量的由自包含的函数构成的代码,全局变量使得程序更难理解和使用。
另一方面,不使用面向对象的编程方法以及类的话,全局变量也许就是Python中最直接保持状态信息的方法(函数在其下次被调用时需要记住的信息):本地变量在函数返回时将会消失,而全局变量不是这样。另一种技术,例如,默认可变参数以及嵌套函数作用域,也能够实现这一点,但是它们与将值推向全局作用域来记忆这种方法相比过于复杂了。
一些程序委任一个单个的模块文件去定义所有的全局变量。只要这样考虑,那么就没有什么不利的因素了。此外,在Python中使用多线程进行并行计算程序实际上是要依靠全局变量的。因为全局变量在并行线程中在不同的函数之间成为了共享内存,所以扮演了通信工具的角色。[1]
到目前为止,在不熟悉编程的情况下,最好尽可能地避免使用全局变量(试试通过传递函数然后返回值来替代一下)。六个月以后,你和你的合作者都会感谢你没有使用那么多全局变量。
[1]多线程与其他的程序并行地运行函数调用,并且得到Python的标准库模块_thread、threading和queue(在Python 2.6中分别是thread、threading和Queue)的支持。由于所有这些线程化函数都在同一进程中运行,全局作用域往往充当它们之间的共享内存。线程用于GUI中长时间运行的任务,以实现广泛地实现非阻塞的操作并利用CPU的能力。这也超出了本书的讨论范围,参见Python库手册和前言中列出的相关图书(例如O'Reilly的Programming Python),可以了解更多细节。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论