一旦迭代器的
__next__()
方法引发StopIteration
,它就必须 在后续通话中继续这样做。没有的实现 遵守此属性被视为已损坏。
但是,对于文件对象:
>>> f = open('test.txt')
>>> list(f)
['a\n', 'b\n', 'c\n', '\n']
>>> next(f)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
>>> f.seek(0)
0
>>> next(f)
'a\n'
文件对象迭代器是否损坏?这只是无法解决的事情之一,因为它会破坏太多依赖它的现有代码吗?
答案 0 :(得分:8)
我认为这是该段的文档错误,而不是io
对象中的错误。 (而且io
对象不是唯一的东西-最简单的是,文件周围的csv.reader
包装器与文件一样可重新启动。)
如果仅将迭代器用作迭代器,则一旦引发它,它将继续引发。但是,如果您在迭代器协议之外调用方法,那么您实际上不再将其用作迭代器,而是将其用作迭代器。在这种情况下,如果可行,将对象“重新填充”似乎是合法的,甚至是惯用的。只要它在作为迭代器发出嘎嘎声时就不会重新填充自身,只有在它发出嘎嘎声时才会超出该范围。
在C ++中类似的情况下,语言委员会很可能会声明这破坏了可替代性,因此,即使您无法在语言上强制使用迭代器,迭代器作为迭代器也会无效。或者为可重复填充的迭代器提出一个全新的协议。 (当然,C ++迭代器与Python迭代器不太一样,但是希望您能理解我的意思。)
但是在Python中,实用性胜过纯粹。我很确定Guido从一开始就打算实现这种行为,并且允许对象执行此操作,并且仍然将其视为迭代器,并且核心开发人员仍会继续这样做,只是没有人考虑过如何写东西足够严格,无法准确地解释它,因为没有人提出要求。
如果您通过提交文档错误来问,我敢打赌,本段将成为脚注,而不是将io
和其他可重新填充的迭代器对象重新分类为实际上不是迭代器。
答案 1 :(得分:2)
是的,根据问题中引用的stdtypes documentation的部分,“文件迭代器”被视为“损坏”。 Python 3迭代器TextIOWrapper
和Python 2迭代器file
都已损坏。
如果您使用的代码假定迭代器严格遵守迭代器协议,那么这是要牢记的一点。举个例子,将itertools.dropwhile
的Python实现与文件迭代器结合使用是有问题的。在另一个进程仍在向日志文件追加行的同时,您可能会通过迭代日志文件来遇到问题。
邮件列表中对此问题进行了讨论。在September 2008 archives中搜索“中断的迭代器”为何被中断?引号:
严格来说,文件对象是损坏的迭代器。
这是设计指南,而不是绝对规则。
还有Terry Reedy:
流阅读器很有可能会在一个调用中返回'',然后在下一个调用中返回非空内容。读取流的迭代器 并产生大小不等的块,直到阻塞为止 只要流是打开的,就没有足够的数据或产生null 提高StopIteration直到蒸汽被关闭并且产生了 最后一块数据。
关闭商店直到关闭商店之间有一个重要的区别。 第二天又关闭了-倒闭了。同样,有一个 缺货到下一次交货之间的差异 且断货且永久中止,或在封闭的道路之间 维修与拆除其他东西。使用相同的符号或 暂时性和永久性状况的信号令人困惑,因此“破裂”。
我认为这种行为不太可能改变语言(“实用胜过纯洁”),但是文档中的语言可能会被软化。如果您要关注此问题,则存在一个开放的问题:issue23455