文件对象迭代器是否“损坏”?

时间:2018-08-15 16:13:53

标签: python iterator

根据documentation

  

一旦迭代器的__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'

文件对象迭代器是否损坏?这只是无法解决的事情之一,因为它会破坏太多依赖它的现有代码吗?

2 个答案:

答案 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中搜索“中断的迭代器”为何被中断?引号:

Miles

  

严格来说,文件对象是损坏的迭代器。

Fredrik Lundh

  

这是设计指南,而不是绝对规则。

还有Terry Reedy

  

流阅读器很有可能会在一个调用中返回'',然后在下一个调用中返回非空内容。读取流的迭代器   并产生大小不等的块,直到阻塞为止   只要流是打开的,就没有足够的数据或产生null   提高StopIteration直到蒸汽被关闭并且产生了   最后一块数据。

     

关闭商店直到关闭商店之间有一个重要的区别。   第二天又关闭了-倒闭了。同样,有一个   缺货到下一次交货之间的差异   且断货且永久中止,或在封闭的道路之间   维修与拆除其他东西。使用相同的符号或   暂时性和永久性状况的信号令人困惑,因此“破裂”。

我认为这种行为不太可能改变语言(“实用胜过纯洁”),但是文档中的语言可能会被软化。如果您要关注此问题,则存在一个开放的问题:issue23455