如何使 python 源代码的编译可重现

How to make the compilation of python source code reproducible

在我的机器上安装 jsonpickle 之后 (pip install jsonpickle==1.4.1 --no-compile),我注意到 ext 子文件夹中的 pandas.py 文件的编译并不总是可重现的。

ext 子文件夹中,我执行了以下 bash 代码以将所有 .py 文件编译为 .pyc 文件:

python -m compileall -d somereldir --invalidation-mode checked-hash

这在 __pycache__ 子目录中创建了一个 pandas.cpython-37.pyc 文件。 然后在 __pycache__ 子目录中执行: xxd pandas.cpython-37.pyc > hex1.hex

如果我再次执行上述步骤并将 hexdump 写入 hex2.hex,我注意到有两行不匹配。

diff hex1.hex hex2.hex
288,289c288,289
< 000011f0: 0029 013e 0200 0000 723f 0000 00da 056e  .).>....r?.....n
< 00001200: 616d 6573 7213 0000 0029 0372 3300 0000  amesr....).r3...
---
> 000011f0: 0029 013e 0200 0000 da05 6e61 6d65 7372  .).>......namesr
> 00001200: 3f00 0000 7213 0000 0029 0372 3300 0000  ?...r....).r3...

我执行了几次,.pyc 文件似乎有两个“版本”,有时它们匹配,有时它们不匹配。

因此,我有几个问题:

  1. 为什么 .pyc 个文件不同?
  2. 如何确保编译后的 .pyc 文件始终相同。
  3. 我检查了其他一些 python 库,它们都生成了可重现的 .pyc 文件,那么这个 pandas.py 文件有什么不同?

pandas.py 文件拆分成更小的部分并进行编译后,我能够在第 135 行确定问题所在:

name_bundle = {k: v for k, v in meta.items() if k in {'name', 'names'}}

回答以下问题:

  1. 第 135 行包含一组 ({'name','names'})。编译后不一定保留集合中元素的顺序。尽管 dictionaries preserve insertion order as of Python 3.7,但我找不到任何有关 Python 3.7.
  2. 集合中元素顺序保存的信息
  3. 将环境变量 PYTHONHASHSEED 设置为固定值。
  4. 这些库可能不包含任何集合。