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函数在完成之前不会产生任何值。
添加回答
举报