在下面的代码中,我尝试使用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
答案 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