为什么要编译 Python 脚本?直接从 .py 文件运行脚本也能正常工作,那么是否有性能优势或其他好处呢?
我还注意到在我的应用程序中,某些文件被编译成 .pyc 文件,而另一些则没有,这是为什么?
为什么要编译 Python 脚本?直接从 .py 文件运行脚本也能正常工作,那么是否有性能优势或其他好处呢?
我还注意到在我的应用程序中,某些文件被编译成 .pyc 文件,而另一些则没有,这是为什么?
这些代码被编译成字节码,可以运行得非常快。
之所以有些文件没有被编译,是因为主脚本(用 python main.py
调用的脚本)每次运行时都会被重新编译。所有导入的脚本将会被编译并存储在硬盘上。
Ben Blank 的重要补充:
值得注意的是,尽管运行已编译的脚本具有更快的启动时间(因为它不需要编译),但它并没有运行得更快。
.pyc文件是已经编译成字节码的Python文件。如果Python找到与您调用的.py文件同名的.pyc文件,则会自动运行该.pyc文件。
《Python简介》中说道编译的Python文件:
从“.pyc”或“.pyo”文件读取代码并不比从“.py”文件中读取代码运行更快;唯一更快的地方是加载速度。
运行.pyc文件的优点在于Python在运行之前无需编译它,因此可以减少开销。由于Python在运行.py文件之前会编译为字节码,因此除此之外不应有任何性能提升。
使用编译的.pyc文件可以获得多少性能提升?这取决于脚本的功能。对于一个简单打印“Hello World”的脚本,编译可能占据总启动和运行时间的大部分时间。但是对于运行时间较长的脚本,相对于总运行时间,编译脚本的成本将降低。
命令行上命名的脚本永远不会保存到.pyc文件中。只有被“主”脚本加载的模块才会以这种方式保存。
优点:
第一:轻微、可消除的混淆。
第二:如果编译结果文件明显变小,则可以获得更快的加载时间。对于网页来说非常不错。
第三:Python 可以跳过编译步骤,初始化加载更快。对于 CPU 和网页来说很好。
第四:你越是注释,与源代码相比,.pyc
或 .pyo
文件就会变得越小。
第五:仅具有 .pyc
或 .pyo
文件的最终用户,很少会因为未还原的更改而向您提出由他们引起的错误。
第六:如果你的目标是嵌入式系统,获得较小的嵌入式文件大小可能代表着一个重要的优势,并且体系结构稳定,因此下面详述的缺点并不会发生。
顶层编译
知道这种方法可以将顶层 Python 源代码文件编译成 .pyc
文件也是很有用的:
python -m py_compile myscript.py
这将删除注释。它会保留文档字符串
。如果您也想删除文档字符串
(您可能需要认真考虑为什么要这样做),那么请改用编译方法...
python -OO -m py_compile myscript.py
如果你使用了-OO
命令行选项,你将会得到一个.pyo
文件而不是.pyc
文件;这两者在代码基本功能方面相同,但docstrings
被删除后文件大小更小(如果一开始有良好的docstrings
则在以后的使用中可读性会降低)。但请参见以下第三个缺点。
请注意,Python会使用.py
文件的日期(如果存在)来决定是否应该执行.py
文件而不是执行.pyc
或.pyo
文件 --- 因此如果修改了.py文件,与之关联的.pyc
或.pyo
文件将过时,失去优化效果。您需要重新编译才能再次获得.pyc
或.pyo
的优化效果,如果可能的话。
缺点:
第一:在.pyc
和.pyo
文件中有一个“魔法cookie”,它指示Python文件编译所在的系统架构。如果将其中一个这样的文件分发到不同类型的环境中,它将无法使用。如果将.pyc
或.pyo
文件分发而不附带相关的.py
文件以重新编译或触摸它,使其取代.pyc
或.pyo
文件,则最终用户也无法修复它。
第二:如果使用上述-OO
命令行选项跳过docstrings
,则没有人能够访问该信息,这可能会导致使用该代码更加困难(甚至是不可能)。
第三:Python的-OO
选项还实现了一些优化,如-O
命令行选项;这可能会导致操作变化。已知的优化包括:
sys.flags.optimize
= 1assert
语句__debug__
= False第四:如果您有意将Python脚本执行文件与类似#!/usr/bin/python
的内容放在第一行,那么这将被剥离在.pyc
和.pyo
文件中,从而失去该功能。
第五:使用选项-O
和-OO
,assert
语句都不会被编译进去,消除了运行时验证的来源。您可以通过使用try
except
来补偿,但这需要放弃assert语句在编译中使用。
第六:有点显然,但如果您编译代码,不仅可能会影响其使用,而且其他人从您的工作中学习的潜力也会大大降低。
还有一件没有提到的事情是源代码编译。例如,nuitka
将Python代码转换成C/C++,并将其编译为可以直接运行在CPU上的二进制代码,而不是运行在较慢的虚拟机上的Python字节码。
这可以显著加速或让你在依赖于C/C++代码的环境中使用Python。
编译过的Python代码运行速度更快。然而,当你将一个.py文件作为导入模块运行时,Python会将其编译和存储起来,只要.py文件没有改变,Python就会一直使用已编译的版本。
对于任何解释型语言,当文件被使用时,这个过程看起来像这样:
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
如前所述,将您的Python代码编译为字节码可以提高性能。这通常由Python自身处理,仅适用于导入的脚本。
您可能希望编译Python代码的另一个原因是保护您的知识产权不被复制和/或修改。
您可以在Python文档中了解更多信息。
运行编译过的脚本确实会有性能差异。如果你运行普通的.py
脚本,机器每次运行时都会进行编译,这需要时间。在现代计算机上,这几乎不可察觉,但随着脚本规模的增大,可能会成为更大的问题。
我们使用编译后的代码分发给没有源代码访问权限的用户。这么做主要是为了防止经验不足的程序员无意中更改或修复错误而没有告知我们。
是的,性能是主要原因,据我所知,也是唯一的原因。
如果您的某些文件没有被编译,则可能是Python无法写入.pyc文件,可能是由于目录权限或其他原因。或者未编译的文件根本没有被加载...(只有在首次加载时才会编译脚本/模块)
初学者可能会认为Python是编译的,因为有 .pyc 文件。.pyc文件是已编译的字节码,然后被解释执行。因此,如果之前运行过python代码并且有 .pyc 文件,第二次运行时会更快,因为无需重新编译字节码。
编译器: 编译器是一种将高级语言翻译成机器语言的代码。
解释器: 解释器也将高级语言转换成可读的二进制相当于机器语言。每次解释器获取要执行的高级语言代码时,都会将代码转换为一个中间代码,再将其转换为机器代码。代码的每个部分都会被解释并按顺序单独执行,如果在代码的某个部分发现错误,则会停止代码的解释而不转换下一组代码。
Sources: http://www.toptal.com/python/why-are-there-so-many-pythons http://www.engineersgarage.com/contribution/difference-between-compiler-and-interpreter
import mylib.py
,Python 将会编译mylib.py
,以便未来的import
语句运行更快。如果你稍后更改了mylib.py
,那么下次导入它时它将被重新编译(Python 使用文件日期来实现这一点)。 - fyngyrz