为什么主运行的Python脚本不像模块一样编译成pyc文件?

34

我理解当你导入一个模块时,该文件会被编译成.pyc文件以加快速度?为什么主文件也不被编译成.pyc?这会减慢速度吗?是不是最好让主文件尽可能小,还是无关紧要?

2个回答

36

当一个模块被加载时,py文件会被"字节编译"为pyc文件。时间戳会记录在pyc文件中。 这样做不是为了让它运行更快,而是为了加载更快。 因此,在加载模块时进行"字节编译"是有意义的。

[编辑:包括注释和参考文献]

来自PEP 3147的“字节码编译”:

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

如何跟踪与Python版本和“py”文件更改相关的字节码编译文件:

它还在编译的字节码“.pyc”文件中插入一个魔数。 每当Python更改字节码格式时(通常在主要版本中),这个数字就会改变。
这确保了为VM先前版本构建的pyc文件不会引起问题。 时间戳用于确保pyc文件与用于创建它的py文件匹配。 当魔数或时间戳不匹配时,重新编译py文件并编写新的pyc文件。

“pyc”文件在Python主要版本之间不兼容。当Python发现具有非匹配魔数的pyc文件时, 它会退回到重新编译源代码的较慢过程。

这就是为什么,如果您仅分发为同一平台编译的“.pyc”文件,如果Python版本发生更改,则不再起作用的原因。

简而言之

如果存在一个后缀为".pyc"的字节编译文件,并且其时间戳表明它是最近的,则将加载该文件,否则Python将回退到较慢的加载".py"文件的方法。 ".py"文件的执行性能不受影响,但是加载".pyc"文件比".py"文件更快。
考虑执行导入b.py的a.py。
Typical total performance = loading time (A.py) + execution time (A.py) + 
                            loading time (B.py) + execution time (B.py) 

Since loading time (B.pyc)  <  loading time (B.py)

You should see a better performance by using the byte compiled "pyc" files. 

如果你有一个大的脚本文件X.py,将其模块化并将内容移动到其他模块中,可以利用字节码编译文件更低的加载时间。另一个推论是,模块往往比脚本或主文件更稳定。因此,它根本没有被编译成字节码。

参考资料


0
编译主脚本对于位于例如/usr/bin的脚本来说可能会很麻烦。.pyc文件生成在同一目录中,从而污染公共位置。

如果速度是一个重要因素,那么我应该让主脚本尽可能简单(这样大部分代码都可以被编译),对吗? - George41
根据Python文档的参考,执行速度不是一个因素。它更快的是加载时间。 - pyfunc
1
然而,正如文档所述:“因此,通过将脚本的大部分代码移动到模块中并具有导入该模块的小型引导脚本,可以减少脚本的启动时间”,但除非您有一个脚本,否则这可能是过度设计。 - matt b
@matt b:是的,只有加载时间缩短了,这确实会导致启动时间缩短。 - pyfunc

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接