4

Python の doctest のように、評価する式と期待される結果をファイルから読み取ることにより、開発中のインタープリターからの出力が正しいことをアサートする簡単なテスト関数を作成しています。これはスキーム用なので、入力ファイルの例は次のようになります

> 42
42

> (+ 1 2 3)
6

このようなファイルを解析できる関数の最初の試みは次のようになり、期待どおりに機能するようです。

def run_test(filename):
    interp = Interpreter()
    response_next = False
    num_tests = 0
    with open(filename) as f:
        for line in f:
            if response_next:
                assert response == line.rstrip('\n')
                response_next = False
            elif line.startswith('> '):
                num_tests += 1
                response = interp.eval(line[2:])
                response = str(response) if response else ''
                response_next = True
    print "{:20} Ran {} tests successfully".format(os.path.basename(filename),
                                                    num_tests)

私はそのようなフラグのファンではないので、フラグを削除して少し改善したかったので、代わりにブロックresponse_next内の次の行を. freenode の IRC で尋ねた内容とは関係のない小さな質問がありました。私は望んでいた助けを得ましたが、代わりに使用する提案も与えられ、結果のリストでインデックスを使用しました。(ペアワイズ ラインにinを使用できるとも言われましたが、後でそのアプローチを調査します。)elifnext(f)f.readlines()groupby()itertools

という質問ですが、なぜその方がいいのか気になったのですが、電車の中でネットが不安定で聞けなかったのでこちらで質問させていただきます。readlines()その場で読み取られるときにすべての行を解析するのではなく、すべてを読み取る方が良いのはなぜですか?

私の気持ちは反対なので、本当に疑問に思っています。すべてが一度に完了するように、一度に1行ずつ解析する方がきれいだと思います。私は通常、Python の配列でインデックスを使用することを避け、イテレータとジェネレータを使用することを好みます。主観的な意見ですので、その人の考えていることを推測して回答することは不可能かもしれませんが、一般的な推奨事項があれば教えていただければ幸いです。

4

3 に答える 3

1

入力全体を一度に読み取るよりも、入力を繰り返し処理する方が確かに Pythonic です。たとえば、これは入力がコンソールの場合に機能します。

配列全体の読み取りとインデックス付けを支持する議論は、ループnext(f)と組み合わせると使用が不明確になる可能性があるということです。ループを aforに置き換えるか、ループ内で呼び出していることを完全に文書化するオプションがあります。forwhile Truenextf

try:
    while True:
        test = next(f)
        response = next(f)
except StopIteration:
    pass

ジョナスが示唆しているように、入力をそれ自体で圧縮することにより、これを達成できます(入力が常にテスト/応答/テスト/応答などの行で構成されることが確実な場合):

for test, response in zip(f, f):               # Python 3
for test, response in itertools.izip(f, f):    # Python 2
于 2012-07-11T12:58:28.060 に答える
0
from itertools import ifilter,imap

def run_test(filename):
    interp = Interpreter()
    num_tests, num_passed, last_result = 0, 0, None
    with open(filename) as f:
        # iterate over non-blank lines
        for line in ifilter(None, imap(str.strip, f)):
            if line.startswith('> '):
                last_result = interp.eval(line[2:])
            else:
                num_tests += 1
                try:
                    assert line == repr(last_test_result)
                except AssertionError, e:
                    print e.message
                else:
                    num_passed += 1
    print("Ran {} tests, {} passed".format(num_tests, num_passed))

...これは、結果行が前のテストを参照していることを単に前提としています。

ファイル全体を一度に利用できるようにすることで特定のメリットが得られない限り、.readlines()は避けます。

また、結果の表現を確認するように比較を変更したため、出力タイプを区別できます。

'6' + '2'
> '62'

60 + 2
> 62
于 2012-07-11T15:49:16.350 に答える
0

すべてを配列に読み込むと、ランダム アクセスと同等になります。配列インデックスを使用して配列を下に移動し、いつでも次の内容を確認し、必要に応じてバックアップすることができます。

バックアップせずにタスクを実行できる場合は、ランダム アクセスは必要なく、ランダム アクセスを使用しない方がクリーンです。あなたの例では、構文は常に単一行 (?) 式であり、その後に予想される応答が続くようです。したがって、式と値のペアごとに 1 回反復し、必要に応じて行を読み取るトップレベルのループを作成します。複数行の式と結果をサポートする場合は、それぞれを読み取る個別の関数を作成できます。完全な式を読み取る関数と、結果 (次の空白行まで) を読み取る関数です。重要なことは、必要なだけ多くの入力を消費し、次の入力のために入力ポインターを適切な状態のままにしておくことができることです。

于 2012-07-11T16:30:24.520 に答える