pycはバイトコードのキャッシュファイルなんだが、実際に中身がどうなっているかはpy_compile.pyのソースコードを読んで理解した。
with open(cfile, 'wb') as fc: fc.write('\0\0\0\0') wr_long(fc, timestamp) marshal.dump(codeobject, fc) fc.flush() fc.seek(0, 0) fc.write(MAGIC)
ここで、codeobjectは
codeobject = __builtin__.compile(codestring, dfile or file,'exec')
でコンパイルしたコードでMAGICはimp.get_magic()で得られたマジックナンバー、wr_longはリトルエンディアンで32bitの整数値を書きこむ関数(py_compileで定義されてる)
つまり、先頭の4バイトがマジックナンバーで次の4バイトにタイムスタンプが続き、その後にmarshalでダンプされたコードオブジェクトが続いたものがpycファイルということだ
実際にpy_compile.pycで確かめてみる。まずマジックナンバーは
>>> import imp >>> imp.get_magic() '\x03\xf3\r\n'
タイムスタンプ
>>> l = long(os.stat('py_compile.py').st_mtime) >>> hex(l & 0xff) '0xbbL' >>> hex((l >>8) & 0xff) '0x8L' >>> hex((l >>16) & 0xff) '0x8fL' >>> hex((l >>24) & 0xff) '0x4dL'
pycをbviで開いて確かめてみる
00000000 03 F3 0D 0A BB 08 8F 4D 63 00 00 00 00 00 00 00 00
確かに先頭からマジックナンバー、タイムスタンプの順に入っていることがわかる。
ところで、なぜ最初に'\0\0\0\0'を入れてからfseekで先頭に戻ってきて改めてマジックナンバーを書き出しているんだろうか?