python解释器如何知道何时编译和更新.pyc文件?

时间:2014-05-21 06:40:52

标签: python

我知道python解释器生成了一个.pyc文件,并且包含了question所说的字节代码。

我认为python解释器正在使用时间戳来检测.pyc是否比.py更新,如果是,则在执行时跳过再次编译。 (makefile的方式)

所以,我做了一个测试,但似乎我错了。

  1. 我写的t.py包含print '123't1.py包含import t。运行命令python t1.py给出了输出123和 生成t.pyc,全部按预期进行。
  2. 然后我将t.py编辑为print '1234'并更新了时间戳 t.pyc touch t.pyc使用python t1.py
  3. 再次运行123,我认为我会1234t.py 确实。所以似乎python解释器仍然知道t.pyc 已更新。
  4. 然后我想知道python解释器是否会在每次运行python t1.py时编译并生成python t1.py。但是,当我多次运行t.pyc时,我发现t.py未更新时.pyc将不会更新。

    所以,我的问题是:python解释器如何知道何时编译和更新.pyc文件?

    更新

    因为python解释器正在使用.pyc文件中存储的时间戳。我认为它记录了.py上次更新的时间。导入时,将其与.py文件的时间戳进行比较。

    所以我试图以这种方式破解它:将操作系统时间更改为旧版本,然后编辑.py文件。 我想当再次导入时,.pyc似乎比.pyc旧,并且python解释器不会更新.pyc但我又错了。

    那么,python解释器是不是以较旧或较新的方式比较这两个时间戳,而是以完全相同的方式?

    以完全相同的方式,我的意思是.py中的时间戳记录了.py上次修改的时间。导入时,它会将时间戳与.pyc的当前时间戳进行比较,如果不相同,则重新编译并更新{{1}}。

2 个答案:

答案 0 :(得分:5)

看起来时间戳直接存储在*.pyc文件中。 python解释器不依赖于文件的最后修改属性,可能是为了避免在复制源树时出现不兼容的字节码问题。

查看the python implementation of the import statement,您可以在_validate_bytecode_header()中找到陈旧的支票。通过它的外观,它提取字节4到7(incl)并将其与源文件的时间码进行比较。如果那些不匹配,则字节码被认为是停滞的,因此重新编译。

在此过程中,它还会根据用于生成给定字节码的源的长度(存储在字节8到11中)检查源文件的长度。

在python实现中,如果其中一个检查失败,则字节码加载器会引发由SourceLoader.get_code()捕获的ImportError,触发重新编译字节码。

注意:这就是在importlib的python版本中完成的。我猜本机版本没有功能差异,但我的C有点太生疏了,无法深入挖掘编译器代码

答案 1 :(得分:0)

如您所想,它实际上基于上次.py更新的时间戳。如果在.py生成之后.pyc已更新,则会重新生成字节码。它与make(仅重新编译新文件)的行为相同。

如果您要导入模块,.pyc会更新,因此您的测试无效,因为您已经执行了代码,而不是导入它我相信。