- 译者序
- 前言
- 第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 各部分练习题的解答
- 作者介绍
- 封面介绍
Python 的视角
当Python运行脚本时,在代码开始进行处理之前,Python还会执行一些步骤。确切地说,第一步是编译成所谓的“字节码”,之后将其转发到所谓的“虚拟机”中。
字节码编译
当程序执行时,Python内部(对大多数用户是完全隐藏的)会先将源代码(文件中的语句)编译成所谓字节码的形式。编译是一个简单的翻译步骤,而且字节码是源代码底层的、与平台无关的表现形式。概括地说,Python通过把每一条源语句分解为单一步骤来将这些源语句翻译成一组字节码指令。这些字节码可以提高执行速度:比起文本文件中原始的源代码语句,字节码的运行速度要快得多。
你会注意到,前面一段所提到的这个过程对于你来说完全是隐藏起来的。如果Python进程在机器上拥有写入权限,那么它将把程序的字节码保存为一个以.pyc为扩展名的文件(".pyc"就是编译过的".py"源代码)。当程序运行之后,你会在那些源代码的附近(也就是说同一个目录下)看到这些文件。
Python这样保存字节码是作为一种启动速度的优化。下一次运行程序时,如果你在上次保存字节码之后没有修改过源代码的话,Python将会加载.pyc文件并跳过编译这个步骤。当Python必须重编译时,它会自动检查源文件和字节码文件的时间戳:如果你又保存了源代码,下次程序运行时,字节码将自动重新创建。
如果Python无法在机器上写入字节码,程序仍然可以工作:字节码将会在内存中生成并在程序结束时简单地丢弃[1]。尽管这样,由于.pyc文件能够加速启动,你最好保证在大型程序中可以写入。字节码文件同样是分发Python程序的方法之一:如果Python找到的都是.pyc文件,它也很乐意运行这个程序,尽管这里没有原始的.py源代码文件(参考本章的“冻结二进制文件”小节获得其他发布的选项)。
Python虚拟机(PVM)
一旦程序编译成字节码(或字节码从已经存在的.pyc文件中载入),之后的字节码发送到通常称为Python虚拟机(Python Virtual Machine,简写为PVM)上来执行。PVM听起来比它本身给人的印象更深刻一些。实际上,它不是一个独立的程序,不需要安装。事实上,PVM就是迭代运行字节码指令的一个大循环,一个接一个地完成操作。PVM是Python的运行引擎,它时常表现为Python系统的一部分,并且它是实际运行脚本的组件。从技术上讲,它才是所谓“Python解释器”的最后一步。
图2-2描述这里介绍的运行时的结构。请记住所有的这些复杂性都是有意地对Python程序员隐藏起来的。字节码的编译是自动完成的,而且PVM也仅仅是安装在机器上的Python系统的一部分。再一次说明,程序员只需简单地编写代码并运行包含有语句的文件。
图 2-2 Python的传统运行执行模式:录入的源代码转换为字节码,之后字节码在Python虚拟机中运行。代码自动被编译,之后再解释
性能的含义
熟悉C和C++这类完全编译语言的读者或许已经发现了Python模式中的一些不同之处。其中一个是,在Python的工作中通常没有"build"或"make"的步骤:代码在写好之后立即运行。另外一个就是,Python字节码不是机器的二进制代码(例如,Intel芯片的指令)。字节码是特定于Python的一种表现形式。
这就是Python代码无法运行得像C或C++代码一样快的原因,就像第1章描述的那样:
PVM循环(而不是CPU芯片)仍然需解释字节码,并且字节码指令与CPU指令相比需要更多的工作。另一方面,和其他经典的解释器不同,这里仍有内部的编译步骤:Python并不需要反复地重分析和重分解每一行语句。实际的效果就是纯Python代码的运行速度介于传统的编译语言和传统的解释语言之间。更多关于Python性能的描述请参看第1章。
开发的含义
Python执行模块的另一个情况是其开发和执行的环境实际上并没有区别。也就是说,编译和执行源代码的系统是同一个系统。这种相似性对于拥有传统编译语言背景的读者来说,更有意义,然而在Python中,编译器总是在运行时出现,并且是运行程序系统的一部分。
这使开发周期大大缩短。在程序开始执行之前不需要预编译和连接;只需要简单地输入并运行代码即可。这同样使Python具有更多的动态语言特性:在运行时,Python程序去构建并执行另一个Python程序是有可能的,而且往往是非常方便的。例如,eval和exec内置模块,能够接受并运行包含Python程序代码的字符串。这种结构是Python能够实现产品定制的原因:因为Python代码可以动态地修改,用户可以改进系统内部的Python部分,而不需要拥有或编译整个系统的代码。
从更基础的角度来说,牢记我们在Python中真正拥有的只有运行时:完全不需要初始的编译阶段,所有的事情都是在程序运行时发生的。这甚至还包括了建立函数和类的操作以及连接的模块。这些事情对于静态语言往往是发生在执行之前的,而在Python中是与程序的执行同时进行的。就像我们看到的那样,实际的效果就是Python比一些读者所用的程序语言带来了更加动态的编程体验。
[1]从严格的意义上讲,只有文件导入的情况下字节码才保存,并不是对顶层文件。我们将会在第3章以及第5部分探讨有关导入的内容。当在交互提示模式下所录入的代码也不会保存为字节码,我们将在第3章说明。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论