3

在下面的代码中,我尝试使用 python 脚本通过将文件读入列表并一次打印 10 行然后询问用户是否要打印接下来的 10 行(打印更多。 .)。问题是 raw_input 一次又一次地询问输入是否我给出'y'或'Y'作为输入并且不继续while循环并且如果我给出任何其他输入while循环制动。我的代码可能不像我学习 python 那样好。

import sys
import string
lines = open('/Users/abc/testfile.txt').readlines()
chunk = 10
start = 0

while 1:
    block = lines[start:chunk]
    for i in block:
        print i
    if raw_input('Print More..') not in ['y', 'Y']:
        break
    start = start + chunk

我得到这个代码的输出是: -

--
10 lines from file

Print More..y
Print More..y
Print More..y
Print More..a
4

3 回答 3

5

您正在构建错误的切片:切片中的第二个参数给出了停止位置,而不是块大小:

chunk = 10
start = 0
stop = chunk
end = len(lines)
while True:
    block = lines[start:stop]     # use stop, not chunk!
    for i in block:
        print i
    if raw_input('Print More..') not in ['y', 'Y'] or stop >= end:
        break
    start += chunk
    stop += chunk
于 2012-11-07T09:54:16.940 回答
3

我不会解释为什么你的代码不起作用以及如何修复它(因为 Tim Pietzcker 已经做了令人钦佩的工作),我将解释如何编写代码,这样这样的问题就不会出现在第一名。

尝试编写自己的显式循环、检查和索引变量是困难且容易出错的。这就是为什么 Python 为您提供了几乎总是不需要这样做的好工具的原因。这就是你使用 Python 而不是 C 的原因。

例如,查看您的程序的以下版本:

count = 10
with open('/Users/abc/testfile.txt', 'r') as testfile:
    for i, line in enumerate(testfile):
        print line
        if (i + 1) % count == 0:
            if raw_input('Print More..') not in ['y', 'Y']:
                break

这比原始代码更短,而且效率也更高(无需读取整个文件然后提前构建一个巨大的列表),但这些并不是使用它的好理由。

一个很好的理由是它更加健壮。这里几乎没有明确的循环逻辑会出错。你甚至不需要记住切片是如何工作的(当然,很容易知道它们[start:stop]不是[start:length]……但是如果你用另一种语言编程比 Python 更频繁,而且你总是在写s.sub(start, length),你会忘记…)。当您到达文件末尾时,它还会自动处理结束,而不是永远继续,为您关闭文件(即使在异常情况下,手动正确处理也很痛苦),以及您尚未编写的其他内容.

另一个很好的理由是它更容易阅读,因为代码尽可能多地告诉你它在做什么,而不是它如何做的细节。

但它仍然不完美,因为仍有一件事你很容易出错:那(i + 1) % count == 0一点。事实上,我在第一次尝试时就弄错了(我忘记了 +1,所以它在第 0、10、20 行……而不是 9、19、29……之后给了我一个“更多”提示)。如果你有一个grouper函数,你可以更简单、更健壮地重写它:

with open('/Users/abc/testfile.txt', 'r') as testfile:
    for group in grouper(testfile, 10):
        for line in group:
            print line
        if raw_input('Print More..') not in ['y', 'Y']:
            break

或者,甚至更好:

with open('/Users/abc/testfile.txt', 'r') as testfile:
    for group in grouper(testfile, 10):
        print '\n'.join(group)
        if raw_input('Print More..') not in ['y', 'Y']:
            break

不幸的是,模块中没有内置这样的 grouper 函数itertools,但你可以很容易地编写一个:

def grouper(iterator, size):
    return itertools.izip(*[iterator]*size)

(如果效率很重要,请在这个网站上搜索——有几个问题,人们会深入比较达到相同效果的不同方法。但通常没关系。就此而言,如果你想了解为什么会这样对事物进行分组,请搜索此站点,因为它已至少解释过两次。)

于 2012-11-07T10:01:43.030 回答
2

正如@Tim Pietzcker 指出的那样,这里不需要更新chunk,只需使用start+10而不是chunk.

block = lines[start:start+10]

并更新开始使用start += 10.

另一种使用的替代解决方案itertools.islice()

 with open("data1.txt") as f:
    slc=islice(f,5)            #replace 5 by 10 in your case
    for x in slc:
        print x.strip()
    while raw_input("wanna see more : ") in("y","Y"):     
        slc=islice(f,5)        #replace 5 by 10 in your case
        for x in slc:
            print x.strip()

这输出:

1
2
3
4
5
wanna see more : y
6
7
8
9
10
wanna see more : n
于 2012-11-07T09:51:35.823 回答