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

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

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

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

Python是一种解释型语言,与编译型语言相反,但由于字节码编译器的存在,区别可能会变得模糊。 这意味着源文件可以直接运行,而不需要显式创build一个可执行文件,然后运行。

我已经了解到,Python是一种解释型语言…

这种stream行的模因是不正确的,或者说是build立在对(自然)语言水平的误解之上的:类似的错误是说“圣经是一本精装书”。 让我解释一下,比喻…

“圣经”是作为一 (实际的,物理的物体被认定为)书籍的意义上的“一本书” 被认为是“圣经副本”的书籍应该有一些共同的基本内容(即使是那些可以用不同的语言,不同的可接受的翻译,脚注等级的注释),然而,这些书是完全可以在许多被认为是根本性的方面有所不同 – 有约束力,装订的颜色,印刷中使用的字体,图示(如果有的话),宽可写边距与否,内置书签的数量和种类, 等等等等。

很有可能一个典型的圣经印刷确实是精装书 – 毕竟,这是一本通常要反复阅读的书,在几个地方加书签,通过寻找给定的章节和诗节指针等,等等,一个好的精装书可以使一个给定的副本在这种使用下持续更长的时间。 然而,这些都是世俗的(实际的)问题,不能用来确定给定的实际书本对象是否是圣经的副本:平装印刷是完全可能的!

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

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

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

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

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

更可能的重点是汇编过程如何“沉重”,“慢”和“高”。 CPython被devise为尽可能快地尽可能轻地编译,尽可能less的仪式 – 编译器只做很less的错误检查和优化,所以它可以快速运行并且在less量内存中运行在需要时自动且透明地运行,而用户甚至不需要知道大部分时间都在进行编辑。 Java和C#在编译过程中通常会接受更多的工作(因此不会执行自动编译),以便更彻底地检查错误并执行更多优化。 它是一个灰度级的连续体,而不是一个黑色或白色的情况,在某个给定的水平上设置一个门槛,并且说只有在这个水平之上,你才称之为“汇编”

没有解释性语言这样的东西。 无论是使用解释器还是编译器,纯粹是实现的一个特征,完全没有任何与语言有关的东西。

每种语言都可以通过解释器或编译器来实现。 绝大多数语言每种types至less有一个实现。 (例如,有C和C ++的解释器,还有用于JavaScript,PHP,Perl,Python和Ruby的编译器)。另外,大多数现代语言实现实际上结合了解释器和编译器(甚至多个编译器)。

语言只是一套抽象的math规则。 口译员是一种语言的几种具体实施策略之一。 这两个人生活在完全不同的抽象层次上。 如果英文是一种打字的语言,“解释语言”这个词就是一个types错误。 “Python是一种解释型语言”这个陈述不仅仅是错误的(因为如果这个错误意味着这个语句甚至是有意义的,即使它是错误的),它也是不合理的 ,因为一种语言永远不能被定义为“解释。”

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

  • IronPython:编译为DLR然后编译为CIL字节码的DLR树。 CIL字节码会发生什么情况取决于您运行的是哪个CLI VES,但是Microsoft .NET,GNU Portable.NET和Novell Mono最终会将其编译为本机机器码。
  • Jython:解释Python源代码,直到它识别出热代码path,然后编译为JVML字节码。 JVML字节码会发生什么情况取决于您正在运行哪个JVM。 Maxine将直接将其编译为未优化的本机代码,直到它识别出热代码path,然后重新编译为优化的本地代码。 HotSpot将首先解释JVML字节码,然后编译热码path以优化机器码。
  • PyPy:编译成PyPy字节码,PyPy字节码然后被PyPy VM解释,直到它识别出它随后编译成本地代码,JVML字节码或CIL字节码的热码path,这取决于你在哪个平台上运行。
  • CPython:编译为CPython字节码,然后解释。
  • 无堆栈Python:编译为CPython字节码,然后解释。
  • Unladen Swallow:编译为CPython字节码,然后解释它,直到识别出编译为LLVM IR的热代码path,然后LLVM编译器将其编译为本地机器代码。

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

不仅“解释性语言”这个术语是不合理的,即使你把它解释为“解释性实施的语言”,这显然是不正确的。 谁告诉你的,显然不知道他在说什么。

尤其是,您看到的.pyc文件是由CPython,Stackless Python或Unladen Swallow生成的caching字节码文件。

这些是由Python解释器在导入.py文件时创build的,它们包含导入模块/程序的“编译字节码”,其思想是从源代码到字节码的“翻译”(只需要完成一次)如果.pyc比相应的.py文件更新,可以在后续import跳过,从而加快启动速度。 但它仍然被解释。

Python(至less是它最常见的实现)遵循一种将原始源码编译成字节码的模式,然后解释虚拟机上的字节码。 这意味着(再次,最常见的实现)既不是一个纯粹的解释器,也不是一个纯粹的编译器。

然而,另一方面,编译过程大部分是隐藏的.pyc文件基本上被当作caching来对待。 他们加快了速度,但通常你不需要意识到它们。 它会根据文件时间/date标记自动使其无效并重新加载(重新编译源代码)。

大概唯一一次我看到一个问题就是编译的字节码文件在某种程度上得到了一个时间戳,这意味着它总是看起来比源文件更新。 由于它看起来更新,源文件从来没有重新编译,所以不pipe你做了什么改变,他们被忽略…

这是给初学者,

在运行之前,Python会自动将脚本编译为编译代码,即所谓的字节代码。

运行脚本不被视为导入,也不会创build.pyc。

例如,如果您有一个脚本文件abc.py ,导入另一个模块xyz.py ,那么在运行abc.py时xyz.pyc将会被创build,因为xyz被导入,但abc.pyc文件将不会被创build 。 py没有被导入。

如果您需要为未导入的模块创build.pyc文件,则可以使用py_compilecompileall模块。

py_compile模块可以手动编译任何模块。 一种方法是交互使用该模块中的py_compile.compile函数:

 >>> import py_compile >>> py_compile.compile('abc.py') 

这会将.pyc写入与abc.py相同的位置(可以使用可选参数cfile覆盖该cfile )。

更多信息: http : //effbot.org/pyfaq/how-do-i-create-a-pyc-file.htm

Python的* .py文件只是一个文本文件,您可以在其中编写一些代码行。 当你试图用“python filename.py”来执行这个文件时

这个命令调用Python虚拟机。 Python虚拟机有两个组件:“编译器”和“解释器”。 解释器不能直接读取* .py文件中的文本,所以这个文本首先被转换成一个针对PVM (不是硬件,而是PVM)的字节码。 PVM执行这个字节码。 * .pyc文件也是生成的,作为运行它的一部分,它执行您在shell或其他文件中的文件的导入操作。

如果这个* .pyc文件已经生成了,那么下次你运行/执行你的* .py文件时,系统会直接加载你的* .pyc文件,这将不需要任何编译(这会节省一些处理器的机器周期)。

生成* .pyc文件后,除非编辑它,否则不需要* .py文件。

Python代码经历了两个阶段。 第一步将代码编译成实际上是字节码的.pyc文件。 然后这个.pyc文件(字节码)使用CPython解释器进行解释。 请参考这个链接。 这里简单地解释了代码编译和执行的过程。

为了加速加载模块,Python在.pyc中caching模块的编译内容。

CPython将其源代码编译为“字节码”,出于性能方面的考虑,只要源文件发生更改,就会将该字节码caching在文件系统上。 这使得加载Python模块的速度更快,因为编译阶段可以被绕过。 当您的源文件是foo.py时,CPython将字节码caching在源旁边的foo.pyc文件中。

在python3中,Python的导入机制被扩展为在每个Python包目录内的单个目录中编写和search字节码caching文件。 这个目录将被称为__pycache__。

以下是描述如何加载模块的stream程图:

在这里输入图像描述

了解更多信息:

ref: PEP3147
ref: “编译”Python文件