协慌网

登录 贡献 社区

如果解释 Python,什么是. pyc 文件?

我已经了解 Python 是一种解释型语言...... 但是,当我查看我的 Python 源代码时,我看到.pyc文件,Windows 将其识别为 “编译的 Python 文件”。这些来自哪里?

答案

我已经理解 Python 是一种解释语言......

这种流行的模因是不正确的,或者更确切地说,是基于对(自然)语言水平的误解而构建的:类似的错误就是说 “圣经是精装书”。让我解释一下比喻......

“圣经” 是 “一本书”,意思是成为一 (实际的,物理对象)书籍; 被确定为 “圣经副本” 的书应该具有一些基本的共同点(内容,即使是那些可以使用不同语言,具有不同的可接受翻译,脚注和其他注释的水平) - 然而,这些书是完全允许在被认为是基本的无数方面有所区别 - 绑定类型,绑定颜色,打印中使用的字体,插图(如果有),宽可写边距与否,内置书签的数量和种类, 等等等等。

很有可能的是,圣经的典型印刷确实是精装书 - 毕竟,它是一本通常意味着一遍又一遍地阅读的书,在几个地方加书签,翻阅寻找给定的章节和诗句指针等等,一个好的精装书绑定可以使给定的副本在这种使用下持续更长时间。然而,这些是平凡的(实际的)问题,不能用于确定给定的实际书籍对象是否是圣经的副本:平装印刷是完全可能的!

类似地,Python 是定义一类语言实现的 “语言”,它必须在某些基本方面都是相似的(语法,大多数语义,除了那些明确允许它们不同的那些部分)但完全允许几乎每个 “实现” 细节都有所不同 - 包括他们如何处理他们给出的源文件,他们是否将源代码编译成某种较低级别的形式(如果是,那么哪种形式 - 以及他们是否保存这些形式编译表格,磁盘或其他地方),他们如何执行所述表格,等等。

经典实现 CPython 通常简称为 “Python” - 但它只是几个生产质量实现中的一个,与 Microsoft 的 IronPython(编译为 CLR 代码,即 “.NET”)并列,Jython (编译为 JVM 代码),PyPy(用 Python 本身编写,可以编译成各种各样的 “后端” 形式,包括 “即时” 生成的机器语言)。它们都是 Python(==“Python 语言的实现”),就像许多表面上不同的书籍对象都可以是圣经(==“圣经的副本”)。

如果你对 CPython 特别感兴趣:它将源文件编译成特定于 Python 的低级表单(称为 “字节码”),在需要时自动执行(当没有与源文件对应的字节码文件时,或者字节码文件比源文件旧,或由不同的 Python 版本编译),通常将字节码文件保存到磁盘(以避免将来重新编译它们)。 OTOH IronPython 通常会编译为 CLR 代码(将它们保存到磁盘或不依赖)和 Jython 保存到 JVM 代码(将它们保存到磁盘或不保存 - 如果保存它们将使用.class扩展名)。

然后,这些较低级别的表单由适当的 “虚拟机”(也称为 “解释器”)执行 - CPython VM,.Net 运行时,Java VM(也称为 JVM)。

因此,从这个意义上来说(典型的实现是做什么的),当且仅当 C#和 Java 是:所有这些都具有首先生成字节码的典型实现策略,然后通过 VM / 解释器执行它时,Python 是一种 “解释语言” 。

更有可能的焦点是编译过程的 “重”,慢和高仪式。 CPython 旨在尽可能快地编译,尽可能轻量级,尽可能少的仪式 - 编译器执行非常少的错误检查和优化,因此它可以快速运行并在少量内存中运行,这样就可以了可以在需要时自动且透明地运行,而无需用户甚至需要知道正在进行编译,大多数情况下。 Java 和 C#通常在编译期间接受更多工作(因此不执行自动编译),以便更彻底地检查错误并执行更多优化。它是灰度级的连续体,而不是黑色或白色的情况,并且将阈值置于某个给定的水平并且仅在该级别之上将其称为 “编译” 将是完全随意的! - )

它们包含字节代码 ,这是 Python 解释器编译源的代码。然后,此代码由 Python 的虚拟机执行。

Python 的文档解释了这样的定义:

Python 是一种解释型语言,与已编译的语言相反,尽管由于字节码编译器的存在,区别可能很模糊。这意味着可以直接运行源文件,而无需显式创建随后运行的可执行文件。

没有解释语言这样的东西。是否使用解释器或编译器纯粹是实现的特性,并且绝对没有任何与该语言有关的内容。

每种语言都可以由解释器或编译器实现。绝大多数语言至少有一种类型的实现。 (例如,有 C 和 C ++ 的解释器,并且有 JavaScript,PHP,Perl,Python 和 Ruby 的编译器。)此外,大多数现代语言实现实际上结合了解释器和编译器(甚至多个编译器)。

语言只是一组抽象的数学规则。解释器是语言的几种具体实现策略之一。这两个人生活在完全不同的抽象层次上。如果英语是键入语言,则术语 “解释语言” 将是类型错误。语句 “Python 是一种解释型语言” 不仅仅是错误的(因为错误意味着该语句甚至有意义,即使它是错误的),它只是简单的没有意义 ,因为语言永远不能被定义为 “解释。”

特别是,如果您查看当前现有的 Python 实现,这些是他们使用的实现策略:

  • IronPython:编译为 DLR 树,然后 DLR 编译为 CIL 字节码。 CIL 字节码会发生什么取决于您运行的 CLI VES,但 Microsoft .NET,GNU Portable.NET 和 Novell Mono 最终会将其编译为本机机器代码。
  • Jython:解释 Python 源代码,直到它识别出热代码路径,然后编译成 JVML 字节码。 JVML 字节码会发生什么取决于您运行的 JVM。 Maxine 将直接将其编译为未优化的本机代码,直到它识别出热代码路径,然后将其重新编译为优化的本机代码。 HotSpot 将首先解释 JVML 字节码,然后最终将热代码路径编译为优化的机器代码。
  • PyPy:编译为 PyPy 字节码,然后由 PyPy VM 解释,直到它识别出热代码路径,然后根据您运行的平台编译成本机代码,JVML 字节码或 CIL 字节码。
  • CPython:编译成 CPython 字节码,然后解释它。
  • Stackless Python:编译成 CPython 字节码,然后解释它。
  • Unladen Swallow:编译成 CPython 字节码,然后解释它直到识别出热代码路径然后编译成 LLVM IR,然后 LLVM 编译器将编译为本机机器代码。

您可能会注意到该列表中的每个实现(以及我未提及的其他一些实现,如 tinypy,Shedskin 或 Psyco)都有一个编译器。事实上,据我所知,目前还没有纯粹解释的 Python 实现,没有计划这样的实现,并且从未有过这样的实现。

“解释语言” 这个术语不仅没有意义,即使你将其解释为 “具有解释性实现的语言”,显然也不是这样。无论谁告诉你,显然不知道他在说什么。

特别是,您看到的.pyc文件是由 CPython,Stackless Python 或 Unladen Swallow 生成的缓存字节码文件。