97

我知道“.pyc”文件是纯文本“.py”文件的编译版本,在运行时创建以使程序运行得更快。但是我观察到一些事情:

  1. 修改“py”文件后,程序行为会发生变化。这表明“py”文件已编译或至少经过某种散列过程或比较时间戳以判断是否应重新编译它们。
  2. 删除所有“.pyc”文件 ( rm *.pyc) 后,有时程序行为会发生变化。这表明它们没有在更新“.py”时被编译。

问题:

  • 他们如何决定何时编译?
  • 有没有办法确保他们在开发过程中进行更严格的检查?
4

2 回答 2

86

仅当该.pycpython 文件由其他脚本导入时,才会创建(并可能覆盖)文件。如果调用了导入,Python 会检查.pyc文件的内部时间戳是否不早于相应的.py文件。如果是,则加载.pyc; 如果不存在或者.pyc不存在,Python会将.py文件编译为 a.pyc并加载它。

“更严格的检查”是什么意思?

于 2013-04-05T17:11:18.690 回答
33

每当导入相应的代码元素时生成 .pyc 文件,并在相应的代码文件已更新时更新。如果 .pyc 文件被删除,它们将自动重新生成。但是,当相应的代码文件被删除时,它们不会被自动删除。

这可能会在文件级重构期间导致一些非常有趣的错误。

首先,您最终可能会推送只能在您的机器上运行而不能在其他人的机器上运行的代码。如果您对已删除的文件有悬空引用,如果您不手动删除相关的 .pyc 文件,这些仍然可以在本地工作,因为 .pyc 文件可以在导入中使用。再加上正确配置的版本控制系统只会将 .py 文件推送到中央存储库,而不是 .pyc 文件,这意味着您的代码可以通过“导入测试”(是否一切都可以导入)就好了,而不是在别人的电脑上工作。

其次,如果你把包变成模块,你可能会遇到一些非常可怕的错误。当您将包(包含文件的__init__.py文件夹)转换为模块(.py 文件)时,曾经代表该包的 .pyc 文件仍然存在。尤其是__init__.pyc遗迹。因此,如果您的包 foo 包含一些无关紧要的代码,那么稍后删除该包并创建一个具有某些功能的文件 foo.pydef bar(): pass并运行:

from foo import bar

你得到:

ImportError: cannot import name bar

因为 python 仍在使用 foo 包中的旧 .pyc 文件,这些文件都没有定义 bar。这在 Web 服务器上尤其成问题,因为 .pyc 文件可能会破坏完全正常运行的代码。

由于这两个原因(可能还有其他原因),您的部署代码和测试代码应该删除 .pyc 文件,例如使用以下 bash 行:

find . -name '*.pyc' -delete

此外,从 python 2.6 开始,您可以运行带有-B标志的 python 以不使用 .pyc 文件。请参阅如何避免 .pyc 文件?更多细节。

另请参阅:如何从项目中删除所有 .pyc 文件?

于 2013-10-14T04:41:22.080 回答