91

dis (Python バイトコードのディスセンブラー) の使用方法を理解したいと思います。dis.dis具体的には、 (または)の出力をどのように解釈する必要がありdis.disassembleますか?

.

これは非常に具体的な例です (Python 2.7.3):

dis.dis("heapq.nsmallest(d,3)")

      0 BUILD_SET             24933
      3 JUMP_IF_TRUE_OR_POP   11889
      6 JUMP_FORWARD          28019 (to 28028)
      9 STORE_GLOBAL          27756 (27756)
     12 LOAD_NAME             29811 (29811)
     15 STORE_SLICE+0  
     16 LOAD_CONST            13100 (13100)
     19 STORE_SLICE+1

JUMP_IF_TRUE_OR_POPetc がバイトコード命令であることがわかります(ただし、興味深いことに、BUILD_SETこのリストには表示されませんが、として機能すると予想されますBUILD_TUPLE)。右側の数字はメモリ割り当てで、左側の数字はgotoの数字だと思います...毎回ほぼ3 ずつ増加していることに気付きました (完全ではありません)。

関数内にラップするとdis.dis("heapq.nsmallest(d,3)"):

def f_heapq_nsmallest(d,n):
    return heapq.nsmallest(d,n)

dis.dis("f_heapq(d,3)")

      0 BUILD_TUPLE            26719
      3 LOAD_NAME              28769 (28769)
      6 JUMP_ABSOLUTE          25640
      9 <44>                                      # what is <44> ?  
     10 DELETE_SLICE+1 
     11 STORE_SLICE+1 
4

2 に答える 2

109

ソース コードを含む文字列を逆アセンブルしようとしていますが、これは Python 2 ではサポートされdis.disいません。したがって、ソース コードをバイト コードとして誤って解釈することに基づく無意味な出力が表示されます。disassemble_stringdis.py

逆アセンブルする前にdis.dis文字列引数をコンパイルするPython 3 では状況が異なります。

Python 3.2.3 (default, Aug 13 2012, 22:28:10) 
>>> import dis
>>> dis.dis('heapq.nlargest(d,3)')
  1           0 LOAD_NAME                0 (heapq) 
              3 LOAD_ATTR                1 (nlargest) 
              6 LOAD_NAME                2 (d) 
              9 LOAD_CONST               0 (3) 
             12 CALL_FUNCTION            2 
             15 RETURN_VALUE         

Python 2 では、コードを に渡す前に自分でコンパイルする必要がありますdis.dis

Python 2.7.3 (default, Aug 13 2012, 18:25:43) 
>>> import dis
>>> dis.dis(compile('heapq.nlargest(d,3)', '<none>', 'eval'))
  1           0 LOAD_NAME                0 (heapq)
              3 LOAD_ATTR                1 (nlargest)
              6 LOAD_NAME                2 (d)
              9 LOAD_CONST               0 (3)
             12 CALL_FUNCTION            2
             15 RETURN_VALUE        

数字の意味は?1左端の数字は、このバイト コードがコンパイルされたソース コードの行番号です。左側の列の数字はバイトコード内の命令のオフセットで、右側の数字はopargsです。実際のバイトコードを見てみましょう:

>>> co = compile('heapq.nlargest(d,3)', '<none>', 'eval')
>>> co.co_code.encode('hex')
'6500006a010065020064000083020053'

見つけたバイト コードのオフセット 0 に、oparg を持つ の65opcode があります。次に (オフセット 3)は opcodeであり、oparg などがあります。opargs はリトルエンディアン順であることに注意してください。したがって、それが 1 です。ドキュメントに記載されていないモジュールには、各オペコードの名前と、各名前のオペコードを示す表が含まれています。LOAD_NAME00006aLOAD_ATTR01000100opcodeopnameopmap

>>> opcode.opname[0x65]
'LOAD_NAME'

oparg の意味は opcode によって異なります。完全なストーリーについては、CPython 仮想マシンの実装を読む必要がありますceval.c。forLOAD_NAMEおよびLOAD_ATTRoparg はco_names、コード オブジェクトのプロパティへのインデックスです。

>>> co.co_names
('heapq', 'nlargest', 'd')

これは、コード オブジェクトLOAD_CONSTのプロパティへのインデックスです。co_consts

>>> co.co_consts
(3,)

の場合CALL_FUNCTION、これは関数に渡す引数の数であり、16 ビットでエンコードされ、通常の引数の数が下位バイトに、キーワード引数の数が上位バイトに含まれます。

于 2012-10-01T12:24:17.137 に答える