[解決済み] スライスされたPythonのバイトコードを実行すると、"SystemError: unknown opcode "が発生することがある。
質問
次の3行のコードからコンパイルされたコードオブジェクトがある。
code = compile('''a = 1 / 0 # bad stuff. avoid running this!
b = 'good stuff'
c = True''', '', 'exec')
を呼び出している。
dis.dis(code)
にディスアセンブルされます。
1 0 LOAD_CONST 0 (1)
2 LOAD_CONST 1 (0)
4 BINARY_TRUE_DIVIDE
6 STORE_NAME 0 (a)
2 8 LOAD_CONST 2 ('good stuff')
10 STORE_NAME 1 (b)
3 12 LOAD_CONST 3 (True)
14 STORE_NAME 2 (c)
16 LOAD_CONST 4 (None)
18 RETURN_VALUE
2行目のバイトコードだけを抽出して実行するにはどうしたらいいのでしょうか。
b = 'good stuff'
?
例えば、最後の行のバイトコードだけを抽出して実行したい場合。
c = True
バイトインデックスから始まる
12
をスライスすれば、コードオブジェクトの
co_code
属性は、生のバイトコードを含んでおり、インデックス
12
を構築するために
types.CodeType
オブジェクトを作成し
exec
を使用します。
import types
code3 = types.CodeType(
code.co_argcount,
code.co_kwonlyargcount,
code.co_nlocals,
code.co_stacksize,
code.co_flags,
code.co_code[12:],
code.co_consts,
code.co_names,
code.co_varnames,
code.co_filename,
code.co_name,
code.co_firstlineno,
code.co_lnotab,
code.co_freevars,
code.co_cellvars)
exec(code3)
print(eval('c'))
の値を正しく出力するようにします。
c
を代入しています。
True
しかし、2行目のバイトコードだけを抽出して実行しようとすると
b = 'good stuff'
であり、インデックス
8
から
12
(を含まない
12
):
code2 = types.CodeType(
code.co_argcount,
code.co_kwonlyargcount,
code.co_nlocals,
code.co_stacksize,
code.co_flags,
code.co_code[8:12],
code.co_consts,
code.co_names,
code.co_varnames,
code.co_filename,
code.co_name,
code.co_firstlineno,
code.co_lnotab,
code.co_freevars,
code.co_cellvars)
exec(code2)
print(eval('b'))
を生成します。
XXX lineno: 1, opcode: 0
Traceback (most recent call last):
File "/path/file.py", line 21, in <module>
exec(code2)
File "", line 1, in <module>
SystemError: unknown opcode
呼び出し
dis.dis(code2)
の正しいバイトコードが含まれていることがわかります。
b = 'good stuff'
:
1 0 LOAD_CONST 2 ('good stuff')
2 STORE_NAME 1 (b)
では、何が足りないのか?
解決方法は?
このトピックに関する文書が見つからず、何が足りないのか理解するのに時間がかかったので、自分自身の質問に答えています。
その結果、すべてのコードブロックが
必須
値を返さないという選択肢はないのです。もし、明示的に
return
ステートメントを使用すると
None
が暗黙のうちに返されることは、問題に示されている最後の2つのバイトコードで明らかです。
16 LOAD_CONST 4 (None)
18 RETURN_VALUE
そこで、インデックスからバイトコードをスライスして
12
の最後の行に対して
c = True
の末尾の暗黙の戻り値を誤って含んでしまいました。
None
幸いなことに、このコードブロックは値を返すという要件を満たしている。
しかし、indexのバイトコードをスライスしてみると、そうではありませんでした。
8
から
12
の2行目には
b = 'good stuff'
を返すための最後の2バイトのコードが抜けているので
None
となり、その結果
SystemError: unknown opcode
の例外が発生します。
そこで、これを解決するために必要なことは、最後の2バイトのコード(実際には合計4バイトのため、バイトコードは実際にはPython 3で"word"コードになりました)をスライスに付加することでした。
code2 = types.CodeType(
code.co_argcount,
code.co_kwonlyargcount,
code.co_nlocals,
code.co_stacksize,
code.co_flags,
code.co_code[8:12] + code.co_code[-4:],
code.co_consts,
code.co_names,
code.co_varnames,
code.co_filename,
code.co_name,
code.co_firstlineno,
code.co_lnotab,
code.co_freevars,
code.co_cellvars)
exec(code2)
print(eval('b'))
そうすると、正しく出力されます。
good stuff
関連
-
python string splicing.join()とsplitting.split()の説明
-
Python Decorator 練習問題
-
Python Pillow Image.save jpg画像圧縮問題
-
PythonでECDSAを実装する方法 知っていますか?
-
[解決済み】Python regex AttributeError: 'NoneType' オブジェクトに 'group' 属性がない。
-
[解決済み】pygame.error: ビデオシステムが初期化されていない
-
[解決済み】 NameError: グローバル名 'xrange' は Python 3 で定義されていません。
-
[解決済み】syntaxError: 'continue' がループ内で適切に使用されていない
-
[解決済み】Python: SyntaxError: キーワードは式になり得ない
-
[解決済み】ValueError: pickleプロトコルがサポートされていません。3、python2 pickleはpython3 pickleでダンプしたファイルを読み込むことができない?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
Pythonの非常に便利な2つのデコレーターを解説
-
python string splicing.join()とsplitting.split()の説明
-
Python 人工知能 人間学習 描画 機械学習モデル作成
-
Evidentlyを用いたPythonデータマイニングによる機械学習モデルダッシュボードの作成
-
Python入門 openを使ったファイルの読み書きの方法
-
風力制御におけるKS原理を深く理解するためのpythonアルゴリズム
-
Python Pillow Image.save jpg画像圧縮問題
-
[解決済み】Pythonスクリプトで「Expected 2D array, got 1D array instead: 」というエラーが発生?
-
[解決済み】TypeError: re.findall()でバイトのようなオブジェクトに文字列パターンを使用することはできません。)
-
[解決済み】Python elifの構文が無効です【終了しました