Python のバイトコード(dis モジュール)で関数を解剖する
dis モジュールを使うと、Python 関数がどのようなバイトコードにコンパイルされるかを確認できます。パフォーマンス最適化やインタプリタの動作理解に有用です。
基本的な使い方
import dis
def add(a, b):
return a + b
dis.dis(add)
出力例:
2 0 LOAD_FAST 0 (a)
2 LOAD_FAST 1 (b)
4 BINARY_ADD
6 RETURN_VALUE各行は「行番号、オフセット、命令、引数」を示します。
命令の意味
| LOAD_FAST | ローカル変数をスタックにプッシュ |
| LOAD_CONST | 定数をスタックにプッシュ |
| BINARY_ADD | スタックから 2 つポップして加算 |
| RETURN_VALUE | スタックトップを返す |
| CALL_FUNCTION | 関数呼び出し |
| STORE_FAST | スタックトップをローカル変数に格納 |
ループの解析
def sum_list(items):
total = 0
for item in items:
total += item
return total
dis.dis(sum_list)
FOR_ITER や JUMP_BACKWARD などのジャンプ命令が現れます。
条件分岐の解析
def check(x):
if x > 0:
return "positive"
else:
return "non-positive"
dis.dis(check)
POP_JUMP_IF_FALSE など条件付きジャンプが使われます。
最適化の確認
def constant_folding():
return 2 + 3
dis.dis(constant_folding)
定数畳み込みにより、コンパイル時に 5 に計算されていることがわかります。
Bytecode オブジェクト
より詳細な解析には Bytecode クラスを使います。
from dis import Bytecode
for instr in Bytecode(add):
print(f"{instr.opname:20} {instr.argrepr}")
バイトコードの理解は、なぜ特定のコードが遅いのか、最適化がどう適用されるかを知る手がかりになります。