2012-11-07 42 views
3

在下面的代码中,我试图使用python脚本通过将文件读入列表并打印10行,然后询问用户是否要打印接下来的10个“更多”命令(unix)线(打印更多..)。 问题在于,如果我给出'y'或'Y'作为输入,并且不继续使用while循环,并且如果给出while循环制动器的其他输入,那么raw_input会一次又一次地询问输入。 我的代码可能不是最好的学习python。为什么while循环在raw_input时仍然存在? (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 
+2

一个方面的注意事项:即使你解决这个问题,程序将永远循环一次你到达最后。如果文件长度为100行,则“行[100:110]”,“行[110:120]”等都是完全有效的空列表。你可能想'为了在f:'而不是写你自己的显式循环和计数器。另外,为什么导入你不需要的模块,为什么要分配'block'两次? – abarnert

回答

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 
+3

这不是我的失望,但这种解决方案导致每次迭代都会使块大小增加10。所以我不太明白,当它肯定会给出错误的结果时,它是如何被接受的答案。 'chunk'这个名字是有误导性的...... –

+1

在循环之外做'islice'并且在每个循环的结尾处仍然没有像编写一个分为10行批量的函数那样pythonic。 – abarnert

+0

@TimPietzcker你说得很对,不需要在这里更新'chunk'。解决方案是错误的,确实值得-1。我想知道他为什么接受它。 –

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

或者只是'block = [start:start + chunk]' – Deestan

+0

@Deestan:当然!谢谢。 –

+0

如果您更喜欢@Deestan的版本,为什么不编辑您的答案以反映它? – abarnert

3

而不是解释为什么你的代码doe无法工作以及如何解决它(因为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) 

(如效率问题,解决这个搜索网站,也有人们在-部门做了几个问题h比较不同的方式来达到同样的效果。但通常没关系。对于这个问题,如果你想了解为什么这个群组的东西,搜索这个网站,因为它已被解释至少两次。)

相关问题