これを行う最も簡単な方法は、ファイルを 1 行ずつスキャンし、一致する行が見つかったらステートメントを追加することです。
次のコードは目的を果たしますが、まったく堅牢ではありません。
def add_info_on_loops(iterable):
in_loop = False
for line in iterable:
if not in_loop:
if line.startswith('for ') or line.startswith('while '):
in_loop = True
yield 'count = 0\n'
yield 'print "Entry of loop"\n'
yield line
yield ' print "Iteration Number:", count'
yield ' count += 1\n'
else:
yield line
else:
if not line.startswith(' '):
in_loop = False
yield 'print "Exit of loop"\n'
yield line
使用法:
>>> code = StringIO("""[code Starts]
... .
... .
... .
... while [condition]:
... [statements]
... [statements]
... [statements]
...
... .
... .
... .
... [code ends]""")
>>> print ''.join(add_info_on_loops(code))
[code Starts]
.
.
.
count = 0
print "Entry of loop"
while [condition]:
print "Iteration Number:", count count += 1
[statements]
[statements]
[statements]
print "Exit of loop"
.
.
.
[code ends]
コードの落とし穴:
- コードは、最上位レベルでループのみを処理します。のようなもの
if condition: for x in a: ...
が認識されません。これは、ループがあるかどうかを確認する前に空白の行を削除することで解決できます (ただし、インデントのさまざまなレベルなどを考慮する必要があります)。
- ループにインデントされていない行があると、コードが壊れます。これは、たとえば、コードを空白行で「分割」し、IDE が空白を削除した場合に発生します。解決策は、インデントされていない行ではなく、空白でもインデントされていない行を待つことです。
- コードはインデント用のタブを処理しません (簡単に修正できます)
- このコードは、1 行のループを処理しません (例:
for x in a: print x
)。この場合、間違った出力が得られます。の後に何かがあるかどうかのチェックを簡単に修正しました:
。
count
ネストされたループのサポートを追加したい場合、単一の変数を使用するのは面倒です。おそらくどこかに整数 ID があり、新しいループを見つけるたびに増分される IDなどcount_0
の変数名を使用する必要があります。count_1
- コードは、キーボードからの空白を持たない括弧付きの式を処理しません。たとえば
for(a,b) in x:
、ループとして検出されず、whilefor (a,b) in x:
が検出されます。これは簡単に解決できます。for
まず、行がandで始まるかどうかを確認while
し、次の文字が文字、数字、アンダースコアであってはなりません (実際には python3 では Unicode 文字も使用でき、これはテストが難しくなりますが、可能です)。
- このコードは、インデントされたループ行で終わるソース コードを処理しません。たとえば
for x in a: indented_last_line_of_code()
、exitは追加されません (この状況が発生しているかどうかを確認するために、関数の外側にprint
チェックを追加することで簡単に修正できます)。in_loop
for
ご覧のとおり、要求したことを実行するコードを書くことはそれほど簡単ではありません。あなたができる最善の方法はast
、コードを解析し、ツリーにアクセスして正しい場所にノードを追加し、コードに再度アクセスしてpythonソースコードを生成することだと思います(通常、ノードにはソースの行に表示があります)これにより、まったく同じコードをコピーして貼り付けることができます)。