什么时候.pyc文件刷新?

Aar*_*hif 84 python pyc python-internals

我知道".pyc"文件是纯文本".py"文件的编译版本,在运行时创建以使程序运行得更快.但是我发现了一些事情:

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

问题:

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

Dav*_*ist 72

.pyc文件被创建(并可能覆盖)仅当蟒蛇文件是否已被其他脚本导入.如果调用导入,Python将检查.pyc文件的内部时间戳是否与相应的.py文件匹配.如果是,它会加载.pyc; 如果它不存在或者如果.pyc它还不存在,Python 会将.py文件编译成a .pyc并加载它.

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

  • 这不太正确.时间戳不需要匹配(并且它们通常不匹配).`.pyc`的时间戳必须比相应的`.py`的时间戳更早*,以触发重新编译. (13认同)
  • @Aaron,您是否可能更改.py文件,并在此过程中使它们变老(例如,通过从另一个目录复制它们,使用保留'修改时间'的操作)? (4认同)
  • 我能解决`rm*.pyc`的问题.我知道如果我强制重新创建所有文件,那么一些问题就会得到解决,这表明文件没有被自己重新编译.我想如果他们确实使用了时间戳,那么就没有办法让这种行为更加严格,但问题仍然存在. (3认同)

Zag*_*ags 29

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

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

首先,您最终可以推送仅适用于您的计算机而不是其他人的代码.如果您对已删除的文件有悬空引用,那么如果您不手动删除相关的.pyc文件,这些文件仍可在本地使用,因为.pyc文件可用于导入.这与以下事实相混淆:正确配置的版本控制系统只会将.py文件推送到中央存储库,而不是.pyc文件,这意味着您的代码可以通过"导入测试"(一切导入正常)就好了而不是在别人的电脑上工作.

其次,如果将软件包转换为模块,则可能会遇到一些非常糟糕的错误.将包(带有文件的__init__.py文件夹)转换为模块(.py文件)时,一旦表示该包的.pyc文件仍然存在.特别是__init__.pyc遗体.所以,如果你的包foo包含一些无关紧要的代码,那么稍后删除该包并使用某个函数创建一个文件foo.py def bar(): pass并运行:

from foo import bar
Run Code Online (Sandbox Code Playgroud)

你得到:

ImportError: cannot import name bar
Run Code Online (Sandbox Code Playgroud)

因为python仍在使用foo包中的旧.pyc文件,其中没有一个定义bar.这在Web服务器上尤其成问题,因为.pyc文件会导致功能完全正常的代码中断.

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

find . -name '*.pyc' -delete
Run Code Online (Sandbox Code Playgroud)

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

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

  • @PiotrDobrogost正确管理的源代码控制涉及不将pyc文件检入源代码.因此,虽然您可以删除本地副本中的文件夹(包括pyc文件),但对于执行git pull的其他人来说,它不会被删除.如果您的部署也涉及git pull,这可能会导致服务器崩溃. (3认同)
  • *特别是,`__init __.pyc`仍然存在.* - 为什么?由于包是删除包的目录意味着删除目录因此没有文件剩下... (2认同)