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

2024-12-20 08:37:00
admin
原创
73
摘要:问题描述:Python 是一种解释型语言。但是为什么我的源目录包含.pycWindows 识别为“已编译的 Python 文件”的文件?解决方案 1:据我了解,Python 是一种解释型语言......这个流行的梗是错误的,或者说,它是基于对(自然)语言水平的误解而建立的:类似的错误是说“圣经是一本精装书”。...

问题描述:

Python 是一种解释型语言。但是为什么我的源目录包含.pycWindows 识别为“已编译的 Python 文件”的文件?


解决方案 1:

据我了解,Python 是一种解释型语言......

这个流行的梗是错误的,或者说,它是基于对(自然)语言水平的误解而建立的:类似的错误是说“圣经是一本精装书”。让我来解释一下这个比喻……

“圣经”是“一本书”,因为它是一(实际的、被识别为)书籍;被识别为“圣经副本”的书籍应该有一些基本的共同点(内容,尽管这些内容可以是不同的语言,有不同的可接受的翻译、脚注和其他注释的级别)——但是,这些书籍在许多被认为是基本方面的方面完全可以有所不同——装订类型、装订颜色、印刷时使用的字体、插图(如果有)、可写边距是否宽、内置书签的数量和种类,等等。

典型的《圣经》印刷很可能确实是精装的——毕竟,这本书通常需要反复阅读,在多个地方做书签,翻阅以寻找给定的章节和诗句指针,等等,而好的精装装订可以使给定的副本在这种使用情况下保存更长时间。然而,这些都是平凡的(实际的)问题,不能用来判断给定的实际书籍对象是否是《圣经》的副本:平装印刷是完全可能的!

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

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

如果您特别对 CPython 感兴趣:它会将源文件编译为 Python 特定的低级形式(称为“字节码”),在需要时自动执行此操作(当没有与源文件对应的字节码文件,或者字节码文件比源代码旧或由不同的 Python 版本编译时),通常会将字节码文件保存到磁盘(以避免将来重新编译它们)。另一方面,IronPython 通常会编译为 CLR 代码(是否将它们保存到磁盘,视情况而定),并将 Jython 编译为 JVM 代码(是否将它们保存到磁盘 -.class如果它保存它们,它将使用扩展)。

然后,这些较低级别的形式由适当的“虚拟机”(也称为“解释器”)执行 - CPython VM、.Net 运行时、Java VM(又名 JVM),视情况而定。

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

更可能的是,重点在于编译过程有多“繁重”、缓慢和繁琐。CPython 旨在尽可能快地、尽可能轻量地进行编译,尽可能少地进行繁琐的编译 —— 编译器几乎不进行错误检查和优化,因此它可以快速运行,并且占用很少的内存,这反过来又让它可以在需要时自动透明地运行,而用户大多数时候甚至不需要知道正在进行编译。Java 和 C# 通常在编译期间接受更多工作(因此不执行自动编译),以便更彻底地检查错误并执行更多优化。这是一个灰度的连续体,而不是黑色或白色的情况,将阈值设置为某个给定级别并说只有在该级别之上才称之为“编译”是完全任意的!-)

解决方案 2:

它们包含字节码,即 Python 解释器将源代码编译成的字节码。然后,Python 的虚拟机会执行此代码。

Python 的文档对该定义的解释如下:

Python 是一种解释型语言,而不是编译型语言,但由于存在字节码编译器,两者的区别可能比较模糊。这意味着可以直接运行源文件,而无需显式创建可执行文件然后运行。

解决方案 3:

不存在解释型语言。使用解释器还是编译器纯粹是实现的特性,与语言本身毫无关系。

每种语言都可以由解释器或编译器实现。绝大多数语言至少有每种类型的一种实现。(例如,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 编译器将其编译为本机机器代码。

  • Cython:将 Python 代码编译为可移植的 C 代码,然后使用标准 C 编译器进行编译

  • Nuitka:将 Python 代码编译为机器相关的 C++ 代码,然后使用标准 C 编译器进行编译

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

不仅“解释型语言”这个术语毫无意义,即使你将其解释为“具有解释型实现的语言”,也显然不是事实。告诉你这个的人显然不知道自己在说什么。

具体来说,.pyc您看到的文件是 CPython、Stackless Python 或 Unladen Swallow 生成的缓存字节码文件。

解决方案 4:

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

解决方案 5:

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

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

在 python3 中,Python 的导入机制得到扩展,可在每个 Python 包目录内的单个目录中写入和搜索字节码缓存文件。此目录将被称为 pycache

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

在此处输入图片描述

更多信息:

参考:PEP3147

参考:“编译的” Python 文件

解决方案 6:

这是给初学者的,

在运行脚本之前,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

解决方案 7:

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

然而,另一方面,编译过程大部分是隐藏的——.pyc 文件基本上被视为缓存;它们可以加快速度,但您通常根本不需要注意它们。它会根据文件时间/日期戳在必要时自动使它们失效并重新加载(重新编译源代码)。

我唯一一次看到这种问题就是,编译后的字节码文件不知何故获得了一个未来很长的时间戳,这意味着它看起来总是比源文件新。由于它看起来较新,源文件从未被重新编译,所以无论你做了什么更改,它们都会被忽略……

解决方案 8:

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

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

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

一旦生成了 .pyc 文件,就不再需要 .py 文件,除非你编辑它。

解决方案 9:

tldr;它是从源代码转换而来的代码,由 python VM 解释并执行。

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

  1. 在 CPU 上执行/运行

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

* 机器码是转换的最后阶段。
* CPU 上要执行的**指令**以机器代码的形式给出。机器代码可以由 CPU**直接执行。**
  1. 将字节码转换为机器码。

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

* 源代码是**人类可读的**代码。这是在使用Pycharm 等**IDE (代码编辑器)时使用的代码。**

现在来看看实际情节。执行任何这些阶段时都有两种方法:一次性转换 [或执行] 代码(又名编译)和逐行转换 [或执行] 代码(又名解释)。

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

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

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

  • 现代语言通常同时涉及编译和解释

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

  • 以 Python 为例,将源代码编译为字节码 [通常以.py 源代码附带的.pyc 文件形式存在],将字节码编译为机器码 [由 PVM 等虚拟机完成,结果是可执行文件],解释机器码/可执行文件以供执行。

  • 什么时候我们可以说一种语言是解释型或编译型的?

+ 答案是查看执行时使用的方法。如果它一次性执行机器代码(==编译),那么它就是编译型语言。另一方面,如果它逐行执行机器代码(==解释),那么它就是解释型语言。
  • 因此,JAVA和Python都是解释型语言。

  • 第三阶段可能会引起混淆,即将字节码转换为机器码。这通常使用称为虚拟机的软件来完成。造成混淆的原因是虚拟机的行为像机器一样,但实际上它不是机器!引入虚拟机是为了实现可移植性,在任何真实的机器上安装虚拟机都可以让我们执行相同的源代码。大多数虚拟机即第三阶段)使用的方法是编译,因此有些人会说它是一种编译型语言。由于虚拟机的重要性,我们经常说这种语言既是编译型又是解释型

解决方案 10:

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

解决方案 11:

区分语言规范和语言实现很重要:

  • 语言规范只是一份包含语言形式规范的文档,具有上下文无关语法和语义规则的定义(如指定原始类型和范围动态)。

  • 语言实现只是一个按照语言规范来实现语言使用的程序(编译器)。

任何编译器都由两个独立的部分组成:前端和后端。前端接收源代码,验证它并将其转换为中间代码。之后,后端将其转换为机器代码,以便在物理机或虚拟机中运行。解释器是一种编译器,但在这种情况下,它可以产生一种在虚拟机中直接执行中间代码的方法。要执行 Python 代码,必须将代码转换为中间代码,之后代码将被“汇编”为可以存储在 .pyc 文件中的字节码,因此每次运行程序时都无需编译程序模块。您可以使用以下方法查看此汇编 Python 代码:

from dis import dis
def a(): pass

dis(a)

任何人都可以用 Python 语言构建静态二进制编译器,也可以构建C 语言解释器。有工具 ( lex/yacc ) 可以简化和自动化构建编译器的过程。

解决方案 12:

机器不懂英语或任何其他语言,它们只懂字节码,必须对字节码进行编译(例如 C/C++、Java)或解释(例如 Ruby、Python),.pyc 是字节码的缓存版本。https:
//www.geeksforgeeks.org/difference-between-compiled-and-interpreted-language/
这里简要介绍了编译型语言和解释型语言之间的区别,TLDR 是解释型语言不需要您在运行之前编译所有代码,因此大多数时候它们对类型等并不严格。

相关推荐
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   984  
  在项目管理领域,CDCP(Certified Data Center Professional)认证评审是一个至关重要的环节,它不仅验证了项目团队的专业能力,还直接关系到项目的成功与否。在这一评审过程中,沟通技巧的运用至关重要。有效的沟通不仅能够确保信息的准确传递,还能增强团队协作,提升评审效率。本文将深入探讨CDCP...
华为IPD流程   0  
  IPD(Integrated Product Development,集成产品开发)是一种以客户需求为核心、跨部门协同的产品开发模式,旨在通过高效的资源整合和流程优化,提升产品开发的成功率和市场竞争力。在IPD培训课程中,掌握关键成功因素是确保团队能够有效实施这一模式的核心。以下将从五个关键成功因素展开讨论,帮助企业和...
IPD项目流程图   0  
  华为IPD(Integrated Product Development,集成产品开发)流程是华为公司在其全球化进程中逐步构建和完善的一套高效产品开发管理体系。这一流程不仅帮助华为在技术创新和产品交付上实现了质的飞跃,还为其在全球市场中赢得了显著的竞争优势。IPD的核心在于通过跨部门协作、阶段性评审和市场需求驱动,确保...
华为IPD   0  
  华为作为全球领先的通信技术解决方案提供商,其成功的背后离不开一套成熟的管理体系——集成产品开发(IPD)。IPD不仅是一种产品开发流程,更是一种系统化的管理思想,它通过跨职能团队的协作、阶段评审机制和市场需求驱动的开发模式,帮助华为在全球市场中脱颖而出。从最初的国内市场到如今的全球化布局,华为的IPD体系在多个领域展现...
IPD管理流程   0  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用