[Python] 不同版本 python 編譯出的 pyc 不相容
用不同版本的 python 編譯出來的 pyc 是不能相容的,
這件事在剛學 python 時就已經知道,本來也沒什麼問題,
沒想到最近產品想要從 CentOS 6.2 改換成 7.0,
所以預設的 python 從 2.6 變成了 2.7,
導致我們之前用 python 2.6 編譯出來的 pyc,在 python 2.7 是不能執行的~
現在我們的解決之道,就是找到正確的 python 版本,
來執行對應的 pyc…
雖然蠻麻煩的,不過似乎也沒什麼其他的解法了,
Decompile 回原本的 py 是一種方式,但是反組譯是不保證成功的…
來看一下不同版本的 pyc 的差異吧~
假設有下面一個非常簡單的 python 檔:
print("hello")
用 py_compile 編譯成 pyc:
python2.6 -m py_compile testpyc.py python2.7 -m py_compile testpyc.py
編譯好之後,用 python2.6 是不能執行 python2.7 編譯出來的 pyc,
反之亦然,會出現 Bad magic number in .pyc file 的錯誤:
testuser@localhost ~ $ python2.6 testpyc_26.pyc hello testuser@localhost ~ $ python2.6 testpyc_27.pyc RuntimeError: Bad magic number in .pyc file testuser@localhost ~ $ python2.7 testpyc_27.pyc hello testuser@localhost ~ $ python2.7 testpyc_26.pyc RuntimeError: Bad magic number in .pyc file
這裡的 magic number 是 pyc 檔頭的最前面 4 個 byte,
不過後兩個 byte 固定是 0d 0a~
每個 python 版本都有不同的 magic number,
可以參考 stackoverflow 這篇文章看看每個 python 版本對應的 magic number~
(或是 python 裡的 import.c)
用 python 也可以很容易的讀出前面兩個會變動的 byte:
testuser@localhost ~ $ python -c 'print open("testpyc_26.pyc").read(2).encode("hex")' d1f2 testuser@localhost ~ $ python -c 'print open("testpyc_27.pyc").read(2).encode("hex")' 03f3
關於 pyc 的結構,The structure of .pyc files 這篇有更多的說明~
如果用檔案比對軟體,比較一下這兩個 pyc,會發現只有檔頭不同:
這樣是不是代表只要修改一下檔頭的 magic number,
就可以讓 python2.7 執行 python2.6 編譯出來的 pyc 呢?
雖然我們曾經想過這件事情,不過很快就被推翻了,
只要找一個稍微複雜一點的 py 編譯一下,
就能發現越複雜的 py 對應的 pyc 檔的內容就越不同~
像我只是在 py 裡面多加上 print os.listdir(“.”),pyc 的差異點就增加了:
結論是:還是只能用正確的 python 去執行 pyc 了… =_=
看是要執行後失敗再換別的,還是根據檔頭的 magic number 判斷都行…