Python 2.6.2のpycファイルフォーマット


関連リンク:
Pythonを例に高度なプログラミング言語プログラムのwire formatと検証を議論する
Python 2.6.2のバイトコード命令セット一覧
.pycファイルは何ですか.
Pythonソースコードのコンパイルの結果は
PyCodeObject(以下、PyCodeObjectの例を「コードオブジェクト」と略称する)では、各役割ドメインに対応するコードオブジェクトがコンパイルされ、co_codeというPyStringObjectはコードオブジェクトのバイトコードを保存している.
Pythonソースファイルはモジュールです.各モジュールの最上位レベルのコードオブジェクトは
marshalはシーケンス化後に得る.pycファイル.marshalはlittle-endianバイト順でデータをシーケンス化する.
関数、クラスの定義など、最上位の役割ドメインにネストされている役割ドメインは、対応するコードオブジェクトはどこにありますか?それぞれが上の役割ドメインのコードオブジェクトにおとなしく横たわっているco_const(定数プール)ドメインには、上位レベルのコードオブジェクトがネストされているため、下の他の役割ドメインを含むコードオブジェクトがネストされています.
PyCodeObjectの構造とmarshalのシーケンス化ロジックは、前のセグメントの2つのリンクを参照してください.
Python 2.6.2のpycファイルの構造
============== <-     。        
pyc_magic     (=0xD1 0xF2 0x0D 0x0A,4  ,    .pyc   )
mtime         (4  ,.pyc           )
============== <-   PyCodeObject  。           
TYPE_CODE     (='c',1  ,PyCodeObject     )
co_argscount  (4  ,       )
co_nlocals    (4  ,    (      )   )
co_stacksize  (4  ,        )
co_flags      (4  ,    )
co_code       (PyStringObject,   )
co_consts     (PyTupleObject,   )
co_names      (PyTupleObject,          )
co_varnames   (PyTupleObject,       )
co_freevars   (PyTupleObject,          )
co_cellvars   (PyTupleObject,                )
co_filename   (PyStringObject,    )
co_firstlineno(4  ,               )
co_lnotab     (PyStringObject,                )
============== <-   PyCodeObject  。    

以上、整数型のドメインには長さが表示され、他のドメインにはタイプが表示されます.ファイルヘッダと後ろのPyCodeObjectの境界線がはっきり見えるように横線で特別に表記してあります.
キーバイトコードはPyStringObjectタイプのオブジェクトに存在するため、このタイプがmarshalでシーケンス化された構造も説明する必要があります.
=========== <- PyStringObject  
TYPE_STRING(='s',1  ,PyStringObject     )
length     (4  ,        )
data       (byte  ,     )
=========== <- PyStringObject  

この2つの構造を理解した後、Python 2.6で発売することができます.2のpycファイルでは、アドレスが0 x 1 Aから始まる4バイト整数で、最上位コードオブジェクトのバイトコードの長さを識別し、長さがlenであると仮定する.0 x 1 Eからlen長のデータが最上位コードオブジェクトのバイトコードである.
pyc_についてmagic
pyc_magicは2バイトの整数で、r(0 x 0 D 0 x 0 Aはr)が加算されます.このように計算されます.
(
Python 2.6 a 1のPython/import.c )
#define MAGIC (62161 | ((long)'\r'<<16) | ((long)'
'<<24))

△marshalが書くときはlittle-endianバイト順を保つことに注意して、rは後ろに走った.
magicにこのようなデータが含まれているのはrが改行文字なので、もし.pycファイルがテキストモードで開く編集されるとmagicが乱れ、Python解釈器がこの破損をロードしようとしています.pycファイルの場合、問題が見つかります.
しかし、その62161はどうやって来たのですか.読書を通して
Include/code.hの注釈では、主要なPythonリリースごとに特別な数字があり、バージョン間で異なることが観察されます.
するとpyc_magicの役割は3つあります.
1、断るのはまったく正常ではない.pycのファイル、例えば普通のテキスト、ピクチャ、音楽、または他のバイナリフォーマット.ファイルの最初の4バイトをチェックすると、多くの無効なファイルが効果的に削除されます.
2、テキストエディタの編集によって破損したファイルを拒否します.
3、対応しないPython解釈器の生成を拒否する.pycファイル.異なるPythonバージョンのmarshalアルゴリズムは異なる可能性があり、仮想マシンが採用するバイトコード命令セットも異なる可能性があるため、念のため異なるバージョンのPython解釈器が生成する.pycファイルは互換性がないと考えられています.
mtimeについて
PyCodeObjectはシーケンス化する.pycファイルの場合、対応するソースファイルの修正時間とともに記録されます.対応するソースファイルが変更すると、そのmtimeが変化し、以前に生成する.pycファイルのmtimeはソースファイルの新しいmtimeと一致しません.これによりPythonインタプリタは、ソースファイルの更新を発見し、再生成することができる.pycファイル.
Python解釈器生成pycファイルは一般的にimportメカニズムでアクティブ化され、読む
Python/import.c importのpyc_が表示されますmagicとmtimeのチェックと書き込み.
ゆうべ作った
Python 2.6.2のバイトコード命令セット一覧、興味のある方はご覧ください~
実際に一つ解読する.pycファイルのバイトコード
例えば、このようなPythonソース:(手当たり次第に書いたので、内容を気にしないでください)
demo.py
class A():
  x = 1

print(A.x) # 1

# increment A.x by 2
A.x += 2
print(A.x) # 3

# create an instance of A
a = A()
print(a.x) # 3

# increment A.x by 4
a.x += 4
print(a.x) # 7
print(A.x) # 3

Python解釈器にdemoにコンパイルする.pyc.他のPythonプログラムでimport demoを勝手に使えば、このファイルを手に入れることができます.ファイルの内容は次のとおりです.
Offset      0  1  2  3  4  5  6  7   8  9  A  B  C  D  E  F

00000000   D1 F2 0D 0A B3 34 04 4A  63 00 00 00 00 00 00 00    ..?.Jc.......
00000010   00 03 00 00 00 40 00 00  00 73 66 00 00 00 64 00   [email protected].
00000020   00 64 05 00 64 01 00 84  00 00 83 00 00 59 5A 00   .d..d..?.?.YZ.
00000030   00 65 00 00 69 01 00 47  48 65 00 00 04 69 01 00   .e..i..GHe...i..
00000040   64 02 00 37 02 5F 01 00  65 00 00 69 01 00 47 48   d..7._..e..i..GH
00000050   65 00 00 83 00 00 5A 02  00 65 02 00 69 01 00 47   e..?.Z..e..i..G
00000060   48 65 02 00 04 69 01 00  64 03 00 37 02 5F 01 00   He...i..d..7._..
00000070   65 02 00 69 01 00 47 48  65 00 00 69 01 00 47 48   e..i..GHe..i..GH
00000080   64 04 00 53 28 06 00 00  00 74 01 00 00 00 41 63   d..S(....t....Ac
00000090   00 00 00 00 00 00 00 00  01 00 00 00 42 00 00 00   ............B...
000000A0   73 0E 00 00 00 65 00 00  5A 01 00 64 00 00 5A 02   s....e..Z..d..Z.
000000B0   00 52 53 28 01 00 00 00  69 01 00 00 00 28 03 00   .RS(....i....(..
000000C0   00 00 74 08 00 00 00 5F  5F 6E 61 6D 65 5F 5F 74   ..t....__name__t
000000D0   0A 00 00 00 5F 5F 6D 6F  64 75 6C 65 5F 5F 74 01   ....__module__t.
000000E0   00 00 00 78 28 00 00 00  00 28 00 00 00 00 28 00   ...x(....(....(.
000000F0   00 00 00 73 07 00 00 00  64 65 6D 6F 2E 70 79 52   ...s....demo.pyR
00000100   00 00 00 00 01 00 00 00  73 02 00 00 00 06 01 69   ........s......i
00000110   02 00 00 00 69 04 00 00  00 4E 28 00 00 00 00 28   ....i....N(....(
00000120   03 00 00 00 52 00 00 00  00 52 03 00 00 00 74 01   ....R....R....t.
00000130   00 00 00 61 28 00 00 00  00 28 00 00 00 00 28 00   ...a(....(....(.
00000140   00 00 00 73 07 00 00 00  64 65 6D 6F 2E 70 79 74   ...s....demo.pyt
00000150   08 00 00 00 3C 6D 6F 64  75 6C 65 3E 01 00 00 00   ....<module>....
00000160   73 10 00 00 00 13 03 08  03 0F 01 08 03 09 01 08   s...............
00000170   03 0F 01 08 01                                     .....

本明細書の前半の解析によれば、最上位コードのバイトコード長は0 x 66=102バイトであり、0 x 1 E−0 x 83の範囲内にある.興味のある方は参考にしてください
Python命令セットリストバイトコード命令を自分で解読してみましょう.
バイトコードの先頭を見ると、まず0 x 64で、これはLOAD_です.CONST命令は、パラメータがあるので、次の2バイト、0 x 00 0 0 x 00、すなわちパラメータが0(little-endianバイト順に注意)である.LOAD_CONST 0は、定数プールの下に0と表記されたオブジェクトを評価スタックに押し付ける.
次に0 x 64、パラメータの0 x 05 0 x 00を接続するとLOAD_CONST 5は,定数プールの下に5と表記されたオブジェクトを評価スタックに押し付ける.
後のバイトコードも法に基づいて類推して認識することができる.
実際にPython標準ライブラリにはバイトコードを抽出するライブラリ、disモジュールがあります.自分で分析するのが面倒ならdisに解決してもらえばいい.
(次のコードではdis.dis(code)の結果が最上位コードオブジェクトのバイトコードであり、
書式:行番号オフセット指令名パラメータ(カッコ内はパラメータの注記))
E:\Python26>python
Python 2.6.2 (r262:71605, Apr 14 2009, 22:40:02) [MSC v.1500 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import dis, marshal
>>> f = open('demo.pyc', 'rb')
>>> magic = f.read(4)
>>> mtime = f.read(4)
>>> code = marshal.load(f)
>>> dis.dis(code)
  1           0 LOAD_CONST               0 ('A')
              3 LOAD_CONST               5 (())
              6 LOAD_CONST               1 (<code object A at 01707EC0, file "demo.py", line 1>)
              9 MAKE_FUNCTION            0
             12 CALL_FUNCTION            0
             15 BUILD_CLASS
             16 STORE_NAME               0 (A)

  4          19 LOAD_NAME                0 (A)
             22 LOAD_ATTR                1 (x)
             25 PRINT_ITEM
             26 PRINT_NEWLINE

  7          27 LOAD_NAME                0 (A)
             30 DUP_TOP
             31 LOAD_ATTR                1 (x)
             34 LOAD_CONST               2 (2)
             37 INPLACE_ADD
             38 ROT_TWO
             39 STORE_ATTR               1 (x)

  8          42 LOAD_NAME                0 (A)
             45 LOAD_ATTR                1 (x)
             48 PRINT_ITEM
             49 PRINT_NEWLINE

 11          50 LOAD_NAME                0 (A)
             53 CALL_FUNCTION            0
             56 STORE_NAME               2 (a)

 12          59 LOAD_NAME                2 (a)
             62 LOAD_ATTR                1 (x)
             65 PRINT_ITEM
             66 PRINT_NEWLINE

 15          67 LOAD_NAME                2 (a)
             70 DUP_TOP
             71 LOAD_ATTR                1 (x)
             74 LOAD_CONST               3 (4)
             77 INPLACE_ADD
             78 ROT_TWO
             79 STORE_ATTR               1 (x)

 16          82 LOAD_NAME                2 (a)
             85 LOAD_ATTR                1 (x)
             88 PRINT_ITEM
             89 PRINT_NEWLINE

 17          90 LOAD_NAME                0 (A)
             93 LOAD_ATTR                1 (x)
             96 PRINT_ITEM
             97 PRINT_NEWLINE
             98 LOAD_CONST               4 (None)
            101 RETURN_VALUE
>>> quit()

P.S.実はこの文は単独で火星を见ています......私は别の1帖をもっときれいにするために分析します.pycファイルフォーマットの部分が取り外されました.もう一つの投稿は:
Pythonを例に高度なプログラミング言語プログラムのwire formatと検証を議論する