3

一般的な質問で申し訳ありません。私が欲しいものの詳細:

ユーザーが Python コードを記述して実行できるようにしたいと考えています。処理されない例外が発生したら、デバッガーで実行を一時停止し、現在の状態/環境/スタック/例外に関する情報を表示して、コードを編集できるようにします。

例外が発生した場所で特別なコード ブロックを編集可能にしたいだけで、他には何もありません (今のところ)。つまり、ループ内で発生した場合は、ループfor内のコード ブロックのみをfor編集可能にしたいのです。これは、ユーザー エディター スコープ内にある最新/最新のコード ブロックである必要があります (他のライブラリや Python ライブラリ内ではありません)。この条件下では、どのコード ブロックを編集するかは常に明確です。


少し迷っていますが、これを行う方法を少し調査しようとしました。

Python のトレースバックは、コード ブロックを直接提供するのではなく、関数とコード行だけを提供します。私はそれを逆算することができましたが、それは私には少しハックなようです. コードの AST でコード ブロックへの参照を何らかの方法で取得できれば、より良い (そしてより自然な) ものになります。

AST を取得する (そしてそれを操作する、つまり操作/編集する) には、おそらくcompiler(どちらが非推奨ですか?) および/またはparserモジュールを使用します。またはastモジュール。ASTで特別なノード/コードブロックを再コンパイルする方法がわかりません。または、関数全体を再コンパイルすることしかできない場合。

4

3 に答える 3

2

astand compile(ビルトイン) をいじってみると、いくつかのノードを変更するために を使用できるようNodeTransformerです...探しているものがわかっている場合は、それらを手動で編集することもできます。

test.py

print 'Dumb Guy'
x = 4 + 4
print x * 3

変更.py

import ast
with open('test.py') as f:
    expr = f.read()

e = ast.parse(expr)
e.body[0].values[0].s = 'Cool Guy'       # Replace the string
e.body[1].targets[0].id = 'herring'      # Change x to herring
e.body[2].values[0].left.id = 'herring'  # Change reference to x to reference to herring
c = compile(e, '<string>', 'exec')
exec(c)

change.py の出力:

クールガイ
24

この方法で本文にコードを追加することもできます (または、リスト要素を置き換える通常の方法で要素を置き換えます)。

p = ast.parse('print "Sweet!"', mode='single')
e.body.extend(p)

そして、再コンパイルして実行するだけです:

c = compile(e, '<string>', 'exec')
exec(c)

関数定義または単一行をそのように置き換えることができます。関数定義には独自の本体があるため、関数 (またはループ) を追加すると、次のようにアクセスできます。

e.body[N].body  # Replace N with the index of the FunctionDef object

_ast.Printただし、単一のastオブジェクト(または_ast.Assign何でも)を実行するために私が知っている唯一の方法は、次のようなことです:

e2 = ast.parse('', mode='exec')
e2.body.append(e.body[0])
exec(compile(e2, '<string>', 'exec'))

これは私には少しハックに思えます。行に関する限り、AST 内の各オブジェクトにはlineno属性があるため、例外から行番号を取得できれば、どのステートメントが例外をスローしたかをかなり簡単に把握できます。

もちろん、これはスタックを例外前の状態に巻き戻す問題を実際に解決するものではありません。これはあなたが本当にやりたいことです。ただし、 pdbを介してそのようなことを行うことは可能かもしれません。

于 2010-07-12T15:27:29.420 に答える
1

その間に私が考え出したことから、これは不可能です。少なくともブロック単位ではありません。Python は関数ごとにコード オブジェクトを生成するため、関数ごとにコードを再コンパイルすることはできますが、コード ブロックごとにはできません。

したがって、唯一の方法は、独自の Python コンパイラを作成することです。

于 2010-08-17T00:37:48.010 に答える
1

Python 用のHAP リモート デバッガーが役に立つのではないでしょうか? ライブ編集があるとは思いませんが、それでもデバッグの側面のいくつかは役立つかもしれません.

于 2010-07-12T16:42:25.150 に答える