问题:如果解释了Python,那么什么是.pyc文件?
我已经了解Python是一种解释语言…
但是,当我看我的 Python源代码时,我看到的.pyc
是Windows标识为“编译的Python文件”的文件。
这些从哪里来?
回答 0
它们包含字节码,这是Python解释器将源代码编译到的字节码。然后,此代码由Python的虚拟机执行。
Python的文档解释了这样的定义:
Python是一种解释型语言,与编译型语言相反,尽管由于字节码编译器的存在,两者之间的区别可能很模糊。这意味着可以直接运行源文件,而无需显式创建然后运行的可执行文件。
回答 1
我已经了解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)。
因此,从这个意义上讲(典型的实现方式是什么),Python是一种“解释语言”,当且仅当C#和Java是:它们都具有一种典型的实现策略,即首先生成字节码,然后通过VM /解释器执行字节码。 。
更有可能的重点是编译过程的“繁重”,缓慢和高仪式性。CPython旨在尽可能快地编译,尽可能轻量级,尽可能少地执行仪式-编译器几乎不执行错误检查和优化,因此它可以快速运行并占用少量内存,这反过来又使它可以运行可以在任何需要的时候自动透明地运行,而用户甚至在大多数情况下都不需要知道正在进行编译。Java和C#通常在编译期间接受更多工作(因此不执行自动编译),以便更彻底地检查错误并执行更多优化。这是灰度的连续体,而不是黑白情况,
回答 2
没有所谓的解释语言。使用解释器还是编译器纯粹是实现的特征,与该语言绝对无关。
每种语言都可以由解释器或编译器实现。绝大多数语言至少每种类型都有一种实现。(例如,有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字节码,然后对其进行解释。
- 无堆栈Python:编译为CPython字节码,然后对其进行解释。
- Unladen Swallow:编译为CPython字节码,然后对其进行解释,直到识别出热代码路径,然后将其编译为LLVM IR,然后LLVM编译器再将其编译为本机代码。
- Cython:将Python代码编译为可移植的C代码,然后使用标准C编译器对其进行编译
- Nuitka:将Python代码编译为机器相关的C ++代码,然后使用标准C编译器进行编译
您可能会注意到,列表中的每个实现(以及我未提及的其他一些实现,例如tinypy,Shedskin或Psyco)都有一个编译器。实际上,据我所知,目前尚没有纯粹解释的Python实现,没有计划好的实现,也从来没有这样的实现。
即使您将“解释语言”一词解释为“具有解释性实现的语言”的含义,这也不是没有道理,但事实并非如此。谁告诉你的,显然不知道他在说什么。
特别是,.pyc
您看到的文件是CPython,Stackless Python或Unladen Swallow生成的缓存字节码文件。
回答 3
它们是由Python解释器在.py
导入文件时创建的,它们包含导入的模块/程序的“已编译字节码”,其想法是从源代码“转换”为字节码(只需要执行一次)。import
如果s .pyc
比相应.py
文件新,则可以在后续s 上跳过,从而加快启动速度。但是它仍然被解释。
回答 4
为了加快模块的加载速度,Python将模块的编译内容缓存在.pyc中。
CPython将其源代码编译为“字节代码”,并且出于性能方面的考虑,只要源文件发生更改,它都会在文件系统上缓存该字节代码。由于可以绕过编译阶段,因此可以更快地加载Python模块。当您的源文件是foo.py时,CPython将字节代码缓存在源代码旁边的foo.pyc文件中。
在python3中,扩展了Python的导入机制,以在每个Python包目录内的单个目录中编写和搜索字节码缓存文件。该目录将称为__pycache__。
这是描述如何加载模块的流程图:
欲获得更多信息:
参考:PEP3147
参考:“已编译” Python文件
回答 5
这是给初学者的,
在运行脚本之前,Python会自动将脚本编译为已编译的代码,即字节代码。
运行脚本不被视为导入,并且不会创建.pyc。
举例来说,如果你有一个脚本文件abc.py是进口的另一个模块xyz.py,当你运行abc.py,xyz.pyc将被创建,因为XYZ是进口的,但没有abc.pyc文件将被创建以来的ABC。 py未导入。
如果您需要为未导入的模块创建.pyc文件,则可以使用py_compile
和compileall
模块。
该py_compile
模块可以手动编译任何模块。一种方法是py_compile.compile
交互使用该模块中的功能:
>>> import py_compile
>>> py_compile.compile('abc.py')
这会将.pyc写入与abc.py相同的位置(您可以使用可选参数覆盖它 cfile
)。
您还可以使用compileall模块自动编译一个或多个目录中的所有文件。
python -m compileall
如果省略了目录名(此示例中为当前目录),则模块将编译在 sys.path
回答 6
Python(至少是最常见的实现)遵循一种将原始源编译为字节码,然后在虚拟机上解释字节码的模式。这意味着(同样,最常见的实现)既不是纯解释器也不是纯编译器。
但是,另一方面是,编译过程基本上是隐藏的-.pyc文件基本上被视为高速缓存;它们加快了速度,但是您通常根本不需要意识到它们。必要时,它会根据文件时间/日期戳自动使它们无效并重新加载(重新编译源代码)。
我唯一一次看到的问题是,经过编译的字节码文件以某种方式获得了未来的时间戳,这意味着它看起来总是比源文件新。由于它看起来较新,因此从未重新编译源文件,因此无论您进行了什么更改,它们都将被忽略…
回答 7
Python的* .py文件只是一个文本文件,您可以在其中编写一些代码行。当您尝试使用“ python filename.py”执行该文件时
此命令调用Python虚拟机。Python虚拟机具有2个组件:“编译器”和“解释器”。解释器无法直接读取* .py文件中的文本,因此该文本首先被转换为针对PVM的字节码(不是硬件,而是PVM)。PVM执行此字节代码。* .pyc文件也作为运行它的一部分生成,该文件对shell中的文件或其他文件中的文件执行导入操作。
如果此* .pyc文件已经生成,则下次您运行/执行* .py文件时,系统会直接加载* .pyc文件,而无需进行任何编译(这将为您节省一些处理器的机器周期)。
生成* .pyc文件后,除非您进行编辑,否则不需要* .py文件。
回答 8
Python代码经历两个阶段。第一步,将代码编译成实际上是字节码的.pyc文件。然后,使用CPython解释器解释此.pyc文件(字节码)。请参考此链接。在这里,用简单的术语解释了代码编译和执行的过程。