为什么要编译Python代码?


241

为什么要编译Python脚本?您可以直接从.py文件运行它们,并且效果很好,那么在性能上有什么优势吗?

我还注意到,我的应用程序中的某些文件被编译为.pyc,而另一些则没有,为什么?


您可能还会注意到,如果您不能共享您的代码(如果这是公司的机密),那么包括更快地启动应用程序在内,您还将获得安全保障。
Please_Dont_Bully_Me_SO_Lords '18

@PSyLoCKe您真的,真的不是。Python字节码确实可读,因为编译器不需要对其进行混淆处理就可以对其进行优化。(并不是说它可以优化很多...)
wizzwizz4 '18

1
一些文件自动编译的原因是因为它们是导入的。例如,如果使用import mylib.py,Python将会编译,mylib.py以便以后的import语句运行更快。如果您以后进行更改mylib.py,则下次导入该文件时将对其进行重新编译(Python使用文件日期来查看是否发生这种情况。)
fyngyrz

Answers:


269

它被编译为字节码,可以使用得越来越快。

未编译某些文件的原因是,python main.py每次运行脚本时都会重新编译与之一起调用的主脚本。所有导入的脚本将被编译并存储在磁盘上。

Ben Blank的重要补充:

值得注意的是,虽然运行已编译的脚本的启动 时间更快(因为它不需要编译),但运行速度不会更快。


259
值得注意的是,虽然运行已编译的脚本的启动时间更快(因为它不需要编译),但运行速度不会更快。
本·布兰克

24
一个常见的误解。感谢分享。
matpie

1
除了不需要编译之外,.pyc文件几乎总是较小。特别是如果您发表很多评论。我的其中一个是.py的28419,但只有.879的.pyc,因此加载时间也更好。最后,您可以通过以下方式预编译顶级脚本:python -m compileall myscript.py
fyngyrz 2014年

1
内存消耗是否有差异?我正在基于mips cpu且只有64MB RAM的嵌入式设备上测试Python,因此启动python脚本的编译版本时,内存使用是否有任何优势?
2014年

1
@valentt:可能不是。我对Python的内部知识了解不多,但是我不认为解析为字节码在Python中会占用大量内存。我无法想到需要大量内存才能记住某种状态的事物。
GeorgSchölly2014年

80

.pyc文件是已编译为字节码的Python。如果Python找到与您调用的.py文件同名的.pyc文件,它将自动运行.pyc文件。

“一个Python简介” 这有关编译Python文件:

从'.pyc'或'.pyo'文件中读取程序比从'.py'文件中读取程序运行得更快。关于“ .pyc”或“ .pyo”文件,唯一更快的是它们的加载速度。

运行.pyc文件的优点是Python不必在运行之前承担编译该文件的开销。由于Python无论如何都将在运行.py文件之前编译为字节码,因此除此以外不应有任何性能改进。

使用编译的.pyc文件可以带来多少改进?这取决于脚本的功能。对于仅打印“ Hello World”的非常简短的脚本,编译可能会占启动和运行总时间的很大一部分。但是,对于运行时间较长的脚本,相对于总运行时间而言,编译脚本的成本会降低。

您在命令行上命名的脚本永远不会保存到.pyc文件中。这样,仅保存由该“主”脚本加载的模块。


3
在很多情况下,很难看到区别,但是我有一个超过300,000行的特定python文件。(这是由另一个脚本生成的用于测试的一堆数学计算)编译需要37秒,而执行仅需要2秒。
wojtow

54

优点:

第一:轻度,可击败的迷惑。

第二:如果编译生成的文件小得多,则加载时间将更快。非常适合网络使用。

第三:Python可以跳过编译步骤。初始负载更快。非常适合CPU和网络。

第四:您发表的评论越多,.pyc.pyo文件与源.py文件相比就越小。

第五:只有.pyc或个.pyo文件的最终用户不太可能向您呈现由他们忘了告诉您的未还原更改引起的错误。

第六:如果您的目标是嵌入式系统,则获得较小尺寸的文件进行嵌入可能会带来很大的好处,并且该体系结构稳定,因此下面将详细介绍的缺点一不起作用。

顶级编译

知道您可以通过.pyc以下方式将顶级python源文件编译成文件是很有用的:

python -m py_compile myscript.py

这将删除注释。它docstrings完好无损。如果您也想摆脱它docstrings(您可能想认真考虑一下为什么这样做),那么可以这样编译...

python -OO -m py_compile myscript.py

...您会得到一个.pyo文件而不是一个.pyc文件;在代码的基本功能方面可以平均分配,但是在剥离后的大小上较小docstrings(如果一开始就很体面的话,就不太容易理解,以后再使用docstrings)。但请参见下面的缺点三。

请注意,python使用.py文件的日期(如果存在)来决定是否应执行.py文件而不是.pycor的.pyo文件---因此,请编辑.py文件,而.pycor .pyo会过时,并且您获得的任何收益都会丢失。您需要重新编译它,以便再次获得.pyc.pyo收益,例如恢复原样。

缺点:

第一:在.pyc.pyo文件中有一个“魔术cookie” ,指示python文件在其中编译的系统体系结构。如果将其中一个文件分发到其他类型的环境中,则会损坏。如果您分发.pyc.pyo而不包含.py要重新编译的关联项,touch那么它将取代.pyc.pyo,最终用户也无法修复它。

第二:如果如上所述docstrings通过使用-OO命令行选项被跳过,则没有人能够获得该信息,这会使代码的使用更加困难(或不可能)。

第三:Python的-OO选项还根据-O命令行选项实现了一些优化。这可能会导致操作发生变化。已知的优化是:

  • sys.flags.optimize = 1
  • assert 语句被跳过
  • __debug__ =错误

第四:如果您故意使python脚本具有#!/usr/bin/python第一行中的顺序可执行文件,则会删除其中的内容.pyc.pyo文件,并且会丢失功能。

第五点:显而易见,但是如果您编译代码,不仅会影响代码的使用,而且通常会严重降低其他人从您的工作中学习的潜力。


10

运行已编译的python可以提高性能。但是,当您将.py文件作为导入的模块运行时,python将会编译并存储该文件,只要.py文件没有更改,它将始终使用编译后的版本。

在使用文件时,使用任何交错语言,过程看起来都是这样的:
1.文件由交错器处理。
2.编译文件
。3.执行已编译的代码。

显然,通过使用预编译的代码,您可以消除第2步,这适用于python,PHP等。

这是一篇有趣的博客文章,解释了它们之间的差异http://julipedia.blogspot.com/2004/07/compiled-vs-interpreted-languages.html
这是一个解释Python编译过程的条目,网址为http://effbot.org/zone /python-compile.htm


9

如前所述,将python代码编译成字节码可以提高性能。这通常由python本身处理,仅适用于导入的脚本。

您可能要编译python代码的另一个原因可能是保护您的知识产权不被复制和/或修改。

您可以在Python文档中阅读有关此内容的更多信息。


2
关于保护您的代码-编译不会有很大帮助。进行混淆处理-但是有意愿的人无论如何都会得到您的代码。
Josh Smeaton

1
如果有足够的时间访问内存或观看CPU的指令,@ josh总是可能的,他们将可以重建您的应用程序。
UnkwnTech

5
但是,正如Unkwntech所说,如果人们有足够的决心,那将永远是可能的。但是我坚信,在大多数情况下,它就足够了,在这种情况下,您通常只希望限制人们“修复”您的代码...
Simon B. Jensen

被编译成字节码的语言一般都不会全部很难反向编译,除非你采取额外的步骤来混淆他们-仅仅是一般编译是不够的。
EJoshuaS-恢复莫妮卡

7

运行已编译的脚本时肯定会有性能差异。如果运行普通.py脚本,则计算机在每次运行时都会对其进行编译,这会花费一些时间。在现代机器上,这几乎不明显,但是随着脚本的增长,它可能会成为更多问题。


7

没有涉及到的是源到源编译。例如,nuitka将Python代码转换为C / C ++,并将其编译为直接在CPU上运行的二进制代码,而不是在较慢的虚拟机上运行的Python字节码。

这可以导致明显的加速,或者可以让您在环境依赖C / C ++代码的情况下使用Python。


4

我们使用编译后的代码来分发给无法访问源代码的用户。基本上是为了阻止没有经验的程序员在不告诉我们的情况下意外更改某些内容或修复错误。


2

是的,表现是主要原因,据我所知,这是唯一的原因。

如果您的某些文件没有得到编译,则可能是由于目录权限之类的原因,Python无法写入.pyc文件。或者,也许从未加载过未编译的文件...(脚本/模块仅在首次加载时才进行编译)


1

初学者认为Python是因为.pyc文件而编译的。.pyc文件是编译后的字节码,然后对其进行解释。因此,如果您之前已经运行过Python代码并拥有.pyc文件,那么它第二次运行会更快,因为它不必重新编译字节码

编译器: 编译器是将高级语言翻译成机器语言的一段代码

口译员: 口译员还将高级语言转换为机器可读的二进制等效项。每次解释器获得要执行的高级语言代码时,它都会先将代码转换为中间代码,然后再将其转换为机器代码。解释代码的每个部分,然后按顺序分别执行,并且在代码的一部分中发现错误,它将停止对代码的解释,而无需翻译下一组代码。

资料来源: http : //www.toptal.com/python/why-are-there-so-many-pythons http://www.engineersgarage.com/contribution/difference-between-compiler-and-interpreter


9
您对“编译器”的定义不正确。从来没有一个编译器可以编译机器代码。编译器仅仅是从一种语言到另一种语言的翻译器。这就是为什么我们说Python“编译”为字节码,Coffeescript“编译”为Java脚本,依此类推。
里奇·斯图尔特
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.