2 回答

TA貢獻(xiàn)1869條經(jīng)驗(yàn) 獲得超4個(gè)贊
mcernak很好地解決并描述了您遇到的問題
然而,這個(gè)問題背后存在一個(gè)設(shè)計(jì)問題:調(diào)用者有時(shí)并不期望生成器,而是非空迭代器
從另一個(gè)角度來看,如果文件丟失了怎么辦?對(duì)于函數(shù)句柄并返回一些哨兵或?qū)⑵涮嵘o調(diào)用者是否更有IOError意義open?
不要試圖強(qiáng)制你的生成器與虐待它的調(diào)用者一起工作,而是考慮
提供兩個(gè)函數(shù)(一個(gè)可以調(diào)用另一個(gè))
為生成器的最大行數(shù)提供一個(gè)參數(shù)(可能是最好的)
# mymod.py
import csv
import itertools
def notbuggy(csvfile, max_rows=None):
with open(csvfile) as stream:
yield from itertools.islice(csv.reader(stream), max_rows)
#!/usr/bin/env python3
# myscript.py
import sys
import mymod
def print_row(row):
print(*row, sep='\t')
def main(csvfile, mode=None):
max_rows = 1 if mode == "first" else None
for row in mymod.notbuggy(csvfile, max_rows):
print_row(row)
if __name__ == '__main__':
main(*sys.argv[1:])
使用時(shí)next(),調(diào)用邏輯必須同意以下之一
永遠(yuǎn)不要在空的可迭代對(duì)象上調(diào)用它(先檢查文件?)
處理來自生成器的異常(StopIteration一些自定義Exception)
處理一些空的哨兵(也許""是一些字符串,None或object..)
然而,調(diào)用者沒有執(zhí)行這些操作,因此保證沒有很好地設(shè)置!
如果調(diào)用者想要多個(gè)行或?qū)⒖丈诒忉尀橹翟趺崔k?除非這些在文檔中以某種方式傳達(dá),否則調(diào)用者總是可以誤用函數(shù)并且不知道為什么它會(huì)出現(xiàn)意外的行為。
>>> next(iter(()))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
>>> g = iter((1,))
>>> next(g)
1
>>> next(g)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
>>> print_row("STOP SENTINEL")
S T O P S E N T I N E L

TA貢獻(xiàn)1846條經(jīng)驗(yàn) 獲得超7個(gè)贊
StopIteration您可以通過以下方式在函數(shù)的詞法范圍內(nèi)捕獲異常buggy:
import csv # essential!
def buggy(csvfile):
with open(csvfile) as stream:
reader = csv.reader(stream)
try:
yield next(reader)
except StopIteration:
yield 'dummy value'
for row in reader:
yield row
您基本上手動(dòng)從迭代器請(qǐng)求第一個(gè)值reader
,然后
如果成功,將從 csv 文件中讀取第一行并將其提供給
buggy
函數(shù)的調(diào)用者如果失敗,就像空 csv 文件的情況一樣,
dummy value
會(huì)產(chǎn)生一些字符串,以防止函數(shù)的調(diào)用者buggy
崩潰
之后,如果 csv 文件不為空,則將在 for 循環(huán)中讀?。ú⑸桑┦S嗟男?。
編輯:為了說明為什么問題中提到的其他變體mymod.py
不起作用,我添加了一些打印語句:
import csv # essential!
def buggy(csvfile):
with open(csvfile) as stream:
reader = csv.reader(stream)
try:
print('reading first row')
firstrow = next(reader)
except StopIteration:
print('no first row exists')
firstrow = None
if firstrow != None:
print('yielding first row: ' + firstrow)
yield firstrow
for row in reader:
print('yielding next row: ' + row)
yield row
print('exiting function open')
運(yùn)行它會(huì)給出以下輸出:
% ./myscript.py empty_input.csv first
reading first row
no first row exists
exiting function open
Traceback (most recent call last):
File "myscript.py", line 15, in <module>
main(*sys.argv[1:])
File "myscript.py", line 9, in main
print_row(next(mymod.buggy(csvfile)))
這表明,如果輸入文件為空,第一個(gè)try..except塊會(huì)正確處理StopIteration異常,并且buggy函數(shù)會(huì)正常繼續(xù)。
在這種情況下,調(diào)用者得到的異常buggy是由于該buggy函數(shù)在完成之前不會(huì)產(chǎn)生任何值。
添加回答
舉報(bào)