为什么主运行的Python脚本不像模块那样编译为pyc文件?
我明白当你导入一个模块时,这个文件会被编译成一个 .pyc
文件,以提高运行速度。那么,为什么主文件也没有被编译成 .pyc
呢?这样会不会导致速度变慢?那是不是应该尽量把主文件做得小一些呢,还是说这没什么关系?
2 个回答
把主要的脚本编译成其他格式会让人很烦,尤其是像在 /usr/bin
这样的地方。因为编译后生成的 .pyc 文件会放在同一个目录里,这样就会把这个公共位置弄得乱七八糟。
当一个模块被加载时,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”文件快。
考虑执行a.py,它导入了b.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,将其模块化并将内容移到其他模块中,可以利用字节编译文件更低的加载时间。
另一个推论是,模块通常比脚本或主文件更稳定。因此,它根本不会被字节编译。
参考资料