Python 将readlines()与索引一起使用还是动态分析行?

Python 将readlines()与索引一起使用还是动态分析行?,python,Python,我正在制作一个简单的测试函数,它通过从文件中读取要计算的表达式和预期结果来断言我正在开发的解释器的输出是正确的,就像python的doctest一样。这是针对scheme的,因此输入文件的示例如下 > 42 42 > (+ 1 2 3) 6 我第一次尝试一个可以解析这样一个文件的函数,如下所示,并且它似乎按照预期工作: def run_test(filename): interp = Interpreter() response_next = False

我正在制作一个简单的测试函数,它通过从文件中读取要计算的表达式和预期结果来断言我正在开发的解释器的输出是正确的,就像python的doctest一样。这是针对scheme的,因此输入文件的示例如下

> 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\u next
标志来稍微改进它,因为我不喜欢这些标志,而是用
next(f)
读取
elif
块中的下一行。关于我在freenode的IRC中询问的问题,我有一个不相关的小问题。我得到了我想要的帮助,但我也得到了建议,使用
f.readlines()
,然后对结果列表使用索引。(我还被告知,我可以在
itertools
中使用
groupby()
来处理成对行,但我稍后将研究这种方法。)

现在说到这个问题,我很好奇为什么这种方法会更好,但是我在火车上的互联网连接很脆弱,我无法问,所以我会在这里问。为什么使用
readlines()
读取所有内容比在动态读取时解析每一行更好


我真的很奇怪,因为我的感觉正好相反,我认为一次一行地解析这些行似乎更干净,这样所有的事情都可以一次性完成。在Python中,我通常避免在数组中使用索引,而更喜欢使用迭代器和生成器。如果这是一个主观的意见,也许不可能回答和猜测这个人的想法,但是如果有一些一般性的建议,我很乐意听到。

迭代地处理输入,而不是一次阅读整个输入,这肯定更符合python;例如,如果输入是控制台,这将起作用

支持读取整个数组并编制索引的一个论点是,如果将
next(f)
for
循环结合使用,则可能不清楚;这里的选项可以是将
for
循环替换为
while True
,或者在
f
循环中完整记录您正在调用的
next

try:
    while True:
        test = next(f)
        response = next(f)
except StopIteration:
    pass
正如Jonas所建议的那样,您可以通过压缩输入本身来实现这一点(如果您确定输入总是由test/response/test/response等行组成):

for test, response in zip(f, f):               # Python 3
for test, response in itertools.izip(f, f):    # Python 2
。。。这只是假设任何结果行都引用前面的测试

我会避免使用.readlines(),除非您能从一次提供整个文件中获得一些特殊好处

我还更改了比较以查看结果的表示形式,因此它可以区分输出类型,即

'6' + '2'
> '62'

60 + 2
> 62

将所有内容读入一个数组就相当于随机访问:您可以使用数组索引在数组中下移,并且可以随时检查下一步内容,并在必要时进行备份

如果您可以在不备份的情况下执行任务,那么您就不需要随机访问,而且不使用它会更干净。在您的示例中,您的语法似乎总是一行(?)表达式,后跟预期的响应。因此,我编写了一个顶级循环,每个表达式-值对迭代一次,根据需要读取行。
如果希望支持多行表达式和结果,可以编写单独的函数来读取每一行:一个读取完整表达式,一个读取结果(直到下一个空行)。重要的是,他们应该能够根据需要使用尽可能多的输入,并将输入指针保持在合理的状态,以便下一次输入

为什么您首先要使用
响应\u next
?您只需检查一行是否以
开头,然后根据该行进行操作。如果是,则为解释器输入。如果没有,则是解释器输出或空行(您可以跳过)。如果这是不可能的,那么您确实可以读取整个文件并一次处理多行。对于这种方法来说,文件似乎不会变得太大。
readlines
如果您保证文件很小,并且需要经常在文件中跳转,那就很好了。在这里描述的情况下,我更喜欢使用
next(f)
方法,因为习惯会一直延续到您需要实际处理大文件的任何时候。@SimeonVisser我希望在下一行说明输出,前面没有任何空行,这就是为什么我添加了这个标志来强制执行它实际上在下面的行上。只是我自己的设计决定。可能是不必要的:-)对于测试,
在itertools.izip(f,f)中响应:
(或者只是
zip
,而不是py3k中的itertools?
'6' + '2'
> '62'

60 + 2
> 62