2 回答

TA貢獻1869條經驗 獲得超4個贊
mcernak很好地解決并描述了您遇到的問題
然而,這個問題背后存在一個設計問題:調用者有時并不期望生成器,而是非空迭代器
從另一個角度來看,如果文件丟失了怎么辦?對于函數句柄并返回一些哨兵或將其提升給調用者是否更有IOError意義open?
不要試圖強制你的生成器與虐待它的調用者一起工作,而是考慮
提供兩個函數(一個可以調用另一個)
為生成器的最大行數提供一個參數(可能是最好的)
# 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:])
使用時next(),調用邏輯必須同意以下之一
永遠不要在空的可迭代對象上調用它(先檢查文件?)
處理來自生成器的異常(StopIteration一些自定義Exception)
處理一些空的哨兵(也許""是一些字符串,None或object..)
然而,調用者沒有執行這些操作,因此保證沒有很好地設置!
如果調用者想要多個行或將空哨兵解釋為值怎么辦?除非這些在文檔中以某種方式傳達,否則調用者總是可以誤用函數并且不知道為什么它會出現意外的行為。
>>> 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貢獻1846條經驗 獲得超7個贊
StopIteration您可以通過以下方式在函數的詞法范圍內捕獲異常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
您基本上手動從迭代器請求第一個值reader
,然后
如果成功,將從 csv 文件中讀取第一行并將其提供給
buggy
函數的調用者如果失敗,就像空 csv 文件的情況一樣,
dummy value
會產生一些字符串,以防止函數的調用者buggy
崩潰
之后,如果 csv 文件不為空,則將在 for 循環中讀取(并生成)剩余的行。
編輯:為了說明為什么問題中提到的其他變體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')
運行它會給出以下輸出:
% ./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)))
這表明,如果輸入文件為空,第一個try..except塊會正確處理StopIteration異常,并且buggy函數會正常繼續。
在這種情況下,調用者得到的異常buggy是由于該buggy函數在完成之前不會產生任何值。
添加回答
舉報