我知道python解释器生成了一个.pyc
文件,并且包含了question所说的字节代码。
我认为python解释器正在使用时间戳来检测.pyc
是否比.py
更新,如果是,则在执行时跳过再次编译。 (makefile的方式)
所以,我做了一个测试,但似乎我错了。
t.py
包含print '123'
,t1.py
包含import
t
。运行命令python t1.py
给出了输出123
和
生成t.pyc
,全部按预期进行。t.py
编辑为print '1234'
并更新了时间戳
t.pyc
touch t.pyc
使用python t1.py
。123
,我认为我会1234
但t.py
确实。所以似乎python解释器仍然知道t.pyc
已更新。然后我想知道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}}。
答案 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
会更新,因此您的测试无效,因为您已经执行了代码,而不是导入它我相信。