簡體   English   中英

使用帶有索引或解析行的readlines()?

[英]Use readlines() with indices or parse lines on the fly?

我正在創建一個簡單的測試函數,通過從文件讀取要評估的表達式和預期結果來斷言我正在開發的解釋器的輸出是正確的,就像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標志來略微改進它,因為我不是這些標志的粉絲,而是用next(f)讀入elif塊中的下一行。 關於我在freenode的IRC詢問的問題,我有一個小小的無關問題。 我得到了我想要的幫助,但我也得到了使用f.readlines()的建議,然后在結果列表中使用索引。 (我還被告知我可以在itertools使用groupby()作為成對行,但我稍后會研究這種方法。)

現在回答這個問題,我很好奇為什么這種方法會更好,但是我的網絡連接在火車上是一個不穩定的,我無法問,所以我會在這里問它。 為什么用readlines()讀取所有內容而不是在運行時讀取每一行時更好?

我真的很納悶,因為我的感覺正好相反,我認為一次解析一條線看起來更干凈,所以一切都完成了。 我通常避免在Python中使用數組中的索引,而更喜歡使用迭代器和生成器。 也許不可能回答和猜測這個人在思考這個主觀意見時的想法,但是如果有一些一般的建議,我會很高興聽到它。

迭代處理輸入而不是一次讀取整個輸入肯定更像Pythonic; 例如,如果輸入是控制台,這將起作用。

支持讀取整個數組和索引的論據是,當與for循環結合使用next(f)可能不清楚; 那些選項可以用一個while True替換for循環,也可以用完全文檔說明你在循環中調用f next

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

正如Jonas建議你可以通過自己壓縮輸入來完成這個(如果你確定輸入將總是由行測試/響應/測試/響應等組成):

for test, response in zip(f, f):               # Python 3
for test, response in itertools.izip(f, f):    # Python 2
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

將所有內容讀入數組會為您提供相應的隨機訪問:您使用數組索引向下移動數組,並且可以隨時檢查下一步並在必要時進行備份。

如果您可以在不進行備份的情況下執行任務,則不需要隨機訪問,如果沒有備份,則更加清晰。 在您的示例中,您的語法似乎始終是單行(?)表達式,后跟預期的響應。 所以,我已經編寫了一個頂級循環,每個表達式 - 值對迭代一次,根據需要讀取行。 如果要支持多行表達式和結果,可以編寫單獨的函數來讀取每個表達式:一個讀取完整表達式,一個讀取結果(直到下一個空白行)。 重要的是它們應該能夠消耗所需的輸入,並將輸入指針保持在合理的狀態以進行下一次輸入。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM