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

时间:2010-06-08 14:27:14

标签: python compiled interpreted-language pyc

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

11 个答案:

答案 0 :(得分:905)

  

我已经理解了这一点   Python是一种解释型语言......

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

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

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

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

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

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

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

因此,在这个意义上(典型的实现是做什么的),当且仅当C#和Java是:所有这些都具有首先生成字节码的典型实现策略,然后通过VM /解释器。

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

答案 1 :(得分:591)

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

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

  

Python是一种解释性语言,如   反对编译的,虽然   区别可能因为模糊而模糊   字节码编译器的存在。   这意味着源文件可以   没有明确地直接运行   创建一个可执行文件然后   运行

答案 2 :(得分:146)

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

每种语言都可以由解释器或编译器实现。绝大多数语言至少有一种类型的实现。 (例如,有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生成的缓存字节码文件。

答案 3 :(得分:59)

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

答案 4 :(得分:36)

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

CPython将其源代码编译为"字节代码",并且出于性能原因,只要源文件发生更改,它就会在文件系统上缓存此字节代码。这使得加载Python模块的速度更快,因为可以绕过编译阶段。当您的源文件是foo.py时,CPython将字节代码缓存在源旁边的foo.pyc文件中。

在python3中,Python的导入机制被扩展为在每个Python包目录内的单个目录中编写和搜索字节代码缓存文件。该目录将被称为__pycache__。

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

enter image description here

了解更多信息:

REF:PEP3147
参考:“Compiled” Python files

答案 5 :(得分:35)

这是初学者,

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

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

例如,如果你有一个脚本文件 abc.py 导入另一个模块 xyz.py ,那么当你运行 abc.py 时自导入xyz以来, xyz.pyc 将被创建,但由于未导入abc.py,因此不会创建 abc.pyc文件

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

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

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

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

您还可以使用compileall模块自动编译目录中的所有文件。

python -m compileall

如果省略目录名(本例中的当前目录),则模块将编译sys.path上找到的所有内容

答案 6 :(得分:20)

Python(至少是它的最常见实现)遵循将原始源编译为字节代码,然后解释虚拟机上的字节代码的模式。这意味着(同样,最常见的实现)既不是纯粹的解释器也不是纯粹的编译器。

然而,另一方面,编译过程大多是隐藏的 - .pyc文件基本上被视为缓存;他们加快了速度,但你通常根本不需要了解它们。它会根据文件时间/日期戳自动使其无效并重新加载(重新编译源代码)。

关于我唯一一次看到这个问题的时候,编译的字节码文件在某种程度上得到了未来的时间戳,这意味着它总是看起来比源文件更新。由于它看起来更新,源文件从未被重新编译,所以无论你做了什么改变,它们都会被忽略......

答案 7 :(得分:12)

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

执行此文件时

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

如果已生成此* .pyc文件,则每次下次运行/执行* .py文件时,系统都会直接加载您的* .pyc文件,该文件不需要任何编译(这样可以节省一些机器周期处理器)。

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

答案 8 :(得分:7)

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

答案 9 :(得分:3)

tldr;它是源代码的转换后的代码,python VM会将其解释为执行。

自下而上的理解:任何程序的最后阶段都是在硬件/机器上运行/执行程序的指令。所以这是执行之前的阶段:

  1. 执行 /在CPU上运行

  2. 将字节码转换为机器码

    • 机器码是转换的最后阶段。

    • 在计算机上给出了
    • 要在CPU上执行的指令。机器代码可以由CPU 直接执行

  3. 字节码转换为机器代码。

    • 字节码是一个中等阶段。可以跳过它以提高效率,但会牺牲可移植性
  4. 源代码转换为字节码。

    • 源代码是人类可读代码。这是在Pycharm之类的 IDE (代码编辑器)上使用时所使用的。

现在是实际情节。进行任何一个阶段时,有两种方法:一次全部转换[或执行]代码(aka 编译)并逐行转换[或执行]代码(aka interpret < / strong>)。

  • 例如,我们可以将源代码编译为bytcoe,将字节码编译为机器代码,解释机器代码以供执行。

  • 某些语言的实现为了提高效率而跳过了第3阶段,即将源代码编译为机器代码,然后解释机器代码以供执行。

  • 某些实现跳过所有中间步骤,直接解释源代码以执行。

  • 现代语言经常涉及两种语言的翻译

  • 例如,
  • JAVA,将源代码编译为BYTCODE(即JAVA源代码的存储方式,作为BYTCODE),将BYTCODE编译为机器代码(使用JVM),并解释机器代码以供执行。 [因此,对于不同的操作系统,JVM的实现方式有所不同,但是相同的JAVA源代码可以在安装了JVM的不同操作系统上执行。]

  • 例如,
  • Python,将源代码编译为bytcode [通常与.py源代码一起找到 .pyc文件],然后将totocde编译为机器代码[由虚拟机完成,例如PVM,结果是一个可执行文件],解释机器代码/可执行以执行。

  • 什么时候可以说一种语言被解释或编译?

    • 答案是通过研究执行中使用的方法。如果它一次执行所有机器代码(==编译),则它是一种编译语言。另一方面,如果它逐行执行机器代码(== interpret),则它是一种解释语言。
  • 因此,JAVA和Python是解释性语言。

  • 可能会由于第三阶段而发生混乱,即将第三阶段代码从字节码转换为机器码。通常,这是通过称为虚拟机的软件完成的。发生混乱是因为虚拟机的行为就像一台计算机,但实际上并非如此!引入虚拟机是为了实现可移植性,在任何REAL机器上都具有VM将使我们能够执行相同的源代码。大多数VM(这是第三阶段)中使用的方法正在编译,因此有人会说这是一种编译语言。对于虚拟机的重要性,我们经常说这类语言是编译和解释的

答案 10 :(得分:-1)

机器不懂英语或任何其他语言,它们只懂字节码,必须编译(例如C / C ++,Java)或解释(例如Ruby,Python),. pyc是字节码的缓存版本。 https://www.geeksforgeeks.org/difference-between-compiled-and-interpreted-language/ 这是有关编译语言与解释语言之间的区别的快速阅读,TLDR是解释语言,不需要您在运行时编译所有代码,因此在大多数情况下它们对输入等不严格。