返回介绍

Python 的视角

发布于 2024-01-29 22:24:17 字数 2701 浏览 0 评论 0 收藏 0

前一节的简要介绍对于脚本语言来说,是相当标准的,并且往往绝大多数Python程序员只需要知道这些就足够了。在文本文件中输入代码,之后在解释器中运行这些代码。然而,当Python“运行”时,透过表面,还有一些事情发生。尽管了解Python内部并不是Python编程所必需的要求,然而对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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文