2012-11-07 44 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比較不同的方式來達到同樣的效果。但通常沒關係。對於這個問題,如果你想了解爲什麼這個羣組的東西,搜索這個網站,因爲它已被解釋至少兩次。)

相關問題