2017-06-23 17 views
9

これまでのところ、私はdocstringsとdisモジュールを多用して実験していましたが、答えが見つからないようです。コンパイルされたスクリプトのバイトコードは、コンパイルされた方法によって異なります

def foo(): 
    pass 

ちょうどこの、何もない:

まず、私は、次の内容のファイルtest.pyを作成します。

その後、プログラムのバイトコードを観察するためにインタプリタを開いた。あなたはこのようにそれを得ることができます:第三モードである間

code = compile(open('test.py').read(), '', 'exec') 

最初の引数は文字列形式のコードで、第二は、デバッグの目的のためである(それは空白のままにすることはO.K.です)。私はsingleexecの両方を試しました。結果は同じです。

この後、disでバイトコードを逆コンパイルできます。

>>> import dis 
>>> dis.dis(code) 

バイトコード出力はこれです:このような簡単なスクリプトのため、

1   0 LOAD_CONST    0 (<code object foo at 0x10a25e8b0, file "", line 1>) 
       3 MAKE_FUNCTION   0 
       6 STORE_NAME    0 (foo) 
       9 LOAD_CONST    1 (None) 
      12 RETURN_VALUE   

リーズナブル。そしてそれも意味がありました。これは、生成されたとtest.pycファイル内部に配置されたバイトコードの結果

$ python -m py_compile test.py 

は、その後、私は、このようなコマンドラインを通してそれをコンパイルしてみました。内容は、再びで分解することができる。

>>> import dis 
>>> dis.dis(open('test.pyc').read()) 

そして、これが出力されます。

>> 0 ROT_THREE  
     1 <243>   2573 
>> 4 <157>   19800 
>> 7 BUILD_CLASS  
     8 DUP_TOPX   0 
    11 STOP_CODE  
    12 STOP_CODE  
>> 13 STOP_CODE  
    14 STOP_CODE  
    15 STOP_CODE  
    16 STOP_CODE  
    17 POP_TOP   
    18 STOP_CODE  
    19 STOP_CODE  
    20 STOP_CODE  
    21 BINARY_AND  
    22 STOP_CODE  
    23 STOP_CODE  
    24 STOP_CODE  
    25 POP_JUMP_IF_TRUE 13 
    28 STOP_CODE  
    29 STOP_CODE  
    30 LOAD_CONST   0 (0) 
    33 MAKE_FUNCTION  0 
    36 STORE_NAME   0 (0) 
    39 LOAD_CONST   1 (1) 
    42 RETURN_VALUE 
    43 STORE_SLICE+0 
    44 ROT_TWO   
    45 STOP_CODE  
    46 STOP_CODE  
    47 STOP_CODE  
    48 DUP_TOPX   0 
    51 STOP_CODE  
    52 STOP_CODE  
    53 STOP_CODE  
    54 STOP_CODE  
    55 STOP_CODE  
    56 STOP_CODE  
    57 POP_TOP   
    58 STOP_CODE  
    59 STOP_CODE  
    60 STOP_CODE  
    61 INPLACE_POWER 
    62 STOP_CODE  
    63 STOP_CODE  
    64 STOP_CODE  
    65 POP_JUMP_IF_TRUE  4 
    68 STOP_CODE  
    69 STOP_CODE  
    70 LOAD_CONST   0 (0) 
    73 RETURN_VALUE 
    74 STORE_SLICE+0 
    75 POP_TOP   
    76 STOP_CODE  
    77 STOP_CODE  
    78 STOP_CODE  
    79 INPLACE_XOR  
    80 STORE_SLICE+0 
    81 STOP_CODE  
    82 STOP_CODE  
    83 STOP_CODE  
    84 STOP_CODE  
    85 STORE_SLICE+0 
    86 STOP_CODE  
    87 STOP_CODE  
    88 STOP_CODE  
    89 STOP_CODE  
    90 STORE_SLICE+0 
    91 STOP_CODE  
    92 STOP_CODE  
    93 STOP_CODE  
    94 STOP_CODE  
    95 STORE_SLICE+0 
    96 STOP_CODE  
    97 STOP_CODE  
    98 STOP_CODE  
    99 STOP_CODE  
    100 POP_JUMP_IF_TRUE  7 
    103 STOP_CODE  
    104 STOP_CODE  
    105 LOAD_GLOBAL  29541 (29541) 
    108 LOAD_GLOBAL  28718 (28718) 
    111 SETUP_EXCEPT  884 (to 998) 
    114 STOP_CODE  
    115 STOP_CODE  
    116 STOP_CODE  
    117 BUILD_TUPLE  28527 
    120 POP_TOP   
    121 STOP_CODE  
    122 STOP_CODE  
    123 STOP_CODE  
    124 POP_JUMP_IF_TRUE  2 
    127 STOP_CODE  
    128 STOP_CODE  
    129 STOP_CODE  
    130 POP_TOP   
    131 INPLACE_XOR  
    132 STORE_SLICE+0 
    133 POP_TOP   
    134 STOP_CODE  
    135 STOP_CODE  
    136 STOP_CODE  
    137 LOAD_LOCALS  
    138 STOP_CODE  
    139 STOP_CODE  
    140 STOP_CODE  
    141 STOP_CODE  
    142 STORE_SLICE+0 
    143 STOP_CODE  
    144 STOP_CODE  
    145 STOP_CODE  
    146 STOP_CODE  
    147 STORE_SLICE+0 
    148 STOP_CODE  
    149 STOP_CODE  
    150 STOP_CODE  
    151 STOP_CODE  
    152 STORE_SLICE+0 
    153 STOP_CODE  
    154 STOP_CODE  
    155 STOP_CODE  
    156 STOP_CODE  
    157 POP_JUMP_IF_TRUE  7 
    160 STOP_CODE  
    161 STOP_CODE  
    162 LOAD_GLOBAL  29541 (29541) 
    165 LOAD_GLOBAL  28718 (28718) 
    168 SETUP_EXCEPT  2164 (to 2335) 
    171 STOP_CODE  
    172 STOP_CODE  
    173 STOP_CODE  
    174 STORE_SUBSCR 
    175 IMPORT_FROM  25711 (25711) 
    178 <117>   25964 
    181 BINARY_LSHIFT 
    182 POP_TOP   
    183 STOP_CODE  
    184 STOP_CODE  
    185 STOP_CODE  
    186 POP_JUMP_IF_TRUE  0 
    189 STOP_CODE  
    190 STOP_CODE  

差は驚異的です。どのようにコンパイルされたかによって、バイトコードにこんなに対照的なのはなぜですか?

答えて

15

.pycファイルの内容はPythonのバイトコード命令の生データではありません。 .pycファイルcontains

  1. 4バイトのマジックナンバー、
  2. 4バイトの修正のタイムスタンプ、及び
  3. マーシャリングコードオブジェクト

あなたは基本的に2回目のゴミを分解しました。

あなたは.pycからコードを逆アセンブルしたい場合は、コードオブジェクトを非整列化、8つのバイトをスキップして、コードオブジェクトにdis.disを呼び出すことができます。.pyc形式はに自由であることを

import dis 
import marshal 

with open('test.pyc', 'b') as f: 
    f.seek(8) 
    dis.dis(marshal.load(f)) 

注意バージョンごとに変更するので、これは必ずしも機能しない可能性があります。実際、参照された記事の時点からすでに変更されています。 Python 3.3では、ソースファイルサイズのタイムスタンプの後に4バイトを追加しました。したがって、3.3以降では、12バイトをスキップする必要があります。

+0

うわー...この「ガベージ」は、どのように正当な見た目のバイトコードに変換されますか? py_compileがスクリプトをコンパイルしない場合、どうしているのですか? –

+0

disassemberはバイナリデータを受け取り、それが有効なバイトコードであるかのように解釈するためです。例えば、ゼロバイトが*意図されたもの*に関係なく、ゼロバイトを「STOP_CODE」と解釈します。 – chepner

+3

@Coldspeed:通常のバイトコードがどのようなものかよくわからないので正当なものです。例えば、 'STOP_CODE'は通常のバイトコードには現れません。 'py_compile'は何のためにPythonファイルをコンパイルしますが、コードオブジェクトの代わりに' .pyc'ファイルにコンパイルします。 – user2357112

関連する問題