3

次のコードでは、Pythonスクリプトを使用して、ファイルをリストに読み込み、一度に10行を印刷してから、次の10行を印刷するかどうかをユーザーに尋ねて「more」コマンド(unix)を作成しようとしています(Print More)。 。)。問題は、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

スライスを間違って作成しています:スライスの2番目のパラメーターは、チャンクサイズではなく、停止位置を示します。

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 は、ほとんどの場合そうする必要のない優れたツールを提供します。そのため、C ではなく Python を使用しています。

たとえば、次のバージョンのプログラムを見てください。

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

これは元のコードよりも短く、はるかに効率的でもあります (事前にファイル全体を読み取って巨大なリストを作成する必要はありません) が、それを使用する正当な理由にはなりません。

正当な理由の 1 つは、はるかに堅牢であることです。ここには、間違いを犯す明示的なループ ロジックはほとんどありません。スライスがどのように機能するかを覚える必要さえありません (確かに、それらが…[start:stop]ではなく[start:length]…ということを学ぶのは簡単ですが、Python よりもはるかに頻繁に別の言語でプログラミングし、常に を書いているs.sub(start, length)場合は、忘れる…)。また、ファイルの最後に到達すると、永久に続行するのではなく、自動的に終了し、ファイルを閉じます (例外が発生した場合でも、手動で修正するのは面倒です)、およびまだ作成していないその他のもの。 .

もう 1 つの正当な理由は、コードがどのように実行されているかの詳細ではなく、コードが何を実行しているかを可能な限り示しているため、はるかに読みやすいということです。

しかし、まだ完璧ではありません。間違いやすいことが 1 つあります。それは、その(i + 1) % count == 0ビットです。実際、最初の試行で間違えました (+1 を忘れたので、9、19、29、… ではなく、0、10、20、… の行の後に「さらに」プロンプトが表示されました)。関数がある場合は、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 回説明されているので、このサイトを検索してください。)

于 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 に答える