为什么while循环粘在raw_input上? (蟒蛇)

时间:2012-11-07 09:48:30

标签: python while-loop raw-input

在下面的代码中,我尝试使用python脚本创建一个“更多”命令(unix),方法是将文件读入列表并一次打印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

3 个答案:

答案 0 :(得分: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

答案 1 :(得分: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

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

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

(如果效率很重要,搜索这个网站 - 有一些问题,人们会对不同方法进行深入比较,以达到同样的效果。但通常无关紧要。就此而言,如果你想要了解为什么这个分组的东西,搜索这个网站,因为它已被解释至少两次。)

答案 2 :(得分: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