Python 是文件对象迭代器";“坏了吗?”;

Python 是文件对象迭代器";“坏了吗?”;,python,iterator,Python,Iterator,根据报告: 一旦迭代器的\uuuuuuuuuuuuuuuuuuuuuuuuuuuuu()方法引发StopIteration,它必须 在以后的通话中继续这样做。不支持的实现 遵守此项规定将被视为已损坏 但是,对于文件对象: >>> f = open('test.txt') >>> list(f) ['a\n', 'b\n', 'c\n', '\n'] >>> next(f) Traceback (most recent call last):

根据报告:

一旦迭代器的
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuu()
方法引发
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'
>f=open('test.txt'))
>>>名单(f)
['a\n'、'b\n'、'c\n'、'\n']
>>>下一个(f)
回溯(最近一次呼叫最后一次):
文件“”,第1行,在
停止迭代
>>>f.seek(0)
0
>>>下一个(f)
“a\n”

文件对象迭代器是否损坏?这只是其中一个无法修复的问题,因为它会破坏太多依赖它的现有代码吗?

我认为这是该段落上的文档错误,而不是
io
对象中的错误。(而且,
io
对象并不是最简单的事情,围绕文件的
csv.reader
包装器与文件一样可以重新启动。)

如果您只是将迭代器用作迭代器,一旦它提升,它将继续提升。但是,如果您在迭代器协议之外调用方法,那么您实际上不再将其用作迭代器,而是将其用作迭代器之外的东西。在这种情况下,如果对象是“可重新填充”的,那么它似乎是合法的,甚至是惯用的。只要它在作为迭代器发出嘎嘎声时从不重新填充自己,只有当它作为其他类型的迭代器发出嘎嘎声时才可以

在类似C++的情况下,语言委员会很可能声明这会破坏可替代性,因此迭代器一旦调用了这种方法,就成为无效的迭代器,即使语言不能强制执行。或者为可再填充迭代器提出一个全新的协议。(当然C++迭代器与Python迭代器并不完全相同,但希望你能理解我的意思。) 但在Python中,实用性胜过纯洁性。我非常确定Guido从一开始就打算这样做,并且允许一个对象这样做,但仍然被视为迭代器,核心开发人员继续打算这样做,只是没有人考虑过如何编写足够严格的内容来准确地解释它,因为没有人问过

如果你通过提交一个docs bug来提问,我敢打赌这一段会得到一个脚注,而不是
io
和其他可重新填充的迭代器对象被重新分类为非实际迭代器。

是的,根据问题中引用的部分,文件迭代器被“视为已损坏”。Python3迭代器和Python2迭代器都已损坏

如果您使用的代码假定迭代器严格遵守迭代器协议,那么这一点值得记住。举一个例子,将的Python实现与文件迭代器结合使用是有缺陷的。当另一个进程仍在向日志文件追加行时,您可能会遇到迭代日志文件的问题

邮件列表中有关于这个问题的讨论。搜索“断开的迭代器”为什么断开?几句话:

:

严格地说,文件对象是中断的迭代器

:

这是一个设计指南,不是绝对的规则

以及:

流读取器很可能在一次调用时返回“”,然后在下一次调用时返回非空的内容。读取流的迭代器 并产生任何大小的块,要么阻塞,直到 只要流是开放的且不存在,就有足够的数据或产生空值 提升停止迭代,直到蒸汽关闭并产生蒸汽 最后一块数据

一家商店在开张前关门,这两者之间有一个重要的区别 第二天,一家公司倒闭了。同样,也存在一个问题 在下一次交货前缺货的商品之间的差异 和缺货和永久停产,或之间的道路封闭 用于维修,而不是拆除其他东西。使用相同的符号或 临时和永久条件的信号混乱,因此“中断”


我认为这种行为不太可能在语言上发生改变(“实用性胜过纯洁性”),但也许文档中的语言会被软化。关于这一点,如果你想遵循它,就存在一个现有的公开问题:

我猜`file.seek(0)`再次调用file对象上的
iter()
,然后调用
next()
,不管你在
seek()
调用了多少次,但是
iter(f)是f
,它无论如何都是相同的迭代器对象。即使不是这样,它也必须神奇地将其重新绑定到
f
。这是哪一个版本的python?python 3.6,但它同样适用于其他版本well@coldspeed从2.3开始,这绝对是真的。可能是2.2(当迭代器和
文件
对象被添加时),但我对此并不乐观。同样的事情也会发生在Jython,等等。实用性胜过纯粹性:)这需要一些古代历史考古学,或者引用对定期提案的讨论来添加更多的概念吗?(我隐约记得Guido在反对Nick Coghlan的
集合
时说了一些类似“是的,这是一个真正的区别,但是没有程序和程序员会愿意做的区别”,因为iterable在调用
iter
两次时总是返回相同值的迭代器,而不会在其间发生突变。)