obj == iter(obj)
是否意味着obj
不能重复迭代,反之亦然?我没有在文档中看到任何这样的措辞,但根据this comment,标准库检查对象是否可重复迭代 by testing if iter(obj) is obj
:
@agf:Python标准库的某些部分依赖于规范的这一部分; they detect whether something is an iterator/generator by testing
if iter(obj) is obj:
,因为真正的迭代器/生成器对象将__iter__
定义为标识函数。如果测试为真,则转换为list
以允许重复迭代,否则,假设对象可重复迭代,并且可以按原样使用它。
- ShadowRanger Jun 3 at 17:23
文档确实说明如果obj
是迭代器,那么iter(obj)
需要返回obj
。但我认为这并不足以得出结论,可以使用iter(obj) is obj
来识别非重复的可迭代对象。
答案 0 :(得分:5)
所有迭代器都是迭代器,但并非所有迭代器都是迭代器。
迭代的唯一requirement是它定义了一个返回迭代器的__iter__()
方法:
需要为容器对象定义一个方法以提供迭代支持:
<强>
container.__iter__()
强>
返回一个迭代器对象。
iterator必须遵循迭代器协议,它有两个要求:
它有一个__iter__()
方法that returns the object itself:
<强>
iterator.__iter__()
强>
返回迭代器对象本身。
它有一个__next__()
方法,可以在每次调用时返回下一个项目,一旦用尽,就会引发StopIteration
on every subsequent call:
一旦迭代器的
__next__()
方法引发StopIteration
,它必须在后续调用中继续这样做。不遵守此属性的实现被视为已损坏。
这些要求意味着迭代器永远不会重复,并且您可以通过确认iter(obj) is obj
是True
来确认迭代是迭代器(因此根据定义不可重复):
def is_unrepeatable(obj):
return iter(obj) is obj
但是:因为iterable的唯一要求是iter(obj)
返回某些迭代器,所以无法证明是可重复的。一个iterable可以定义一个__iter__()
方法,每次调用它时返回一个具有不同行为的迭代器:例如,它可以返回一个迭代器,它在第一次调用时迭代它的元素,但是在后续调用中,返回一个迭代器这会立即引发StopIteration
。
这种行为会很奇怪(而且很烦人),但并不是禁止的。这是一个不可重复的可迭代类的例子,它不是迭代器:
class Unrepeatable:
def __init__(self, iterable):
self.iterable = iterable
self.exhausted = False
def __iter__(self):
if self.exhausted:
return
else:
self.exhausted = True
yield from self.iterable
>>> x = Unrepeatable([1,2,3])
>>> list(x)
[1, 2, 3]
>>> list(x)
[]
>>> iter(x) is x
False
>>>
我会毫不犹豫地称这样一个“伪造的迭代器”表现得很糟糕,我想不出你在野外找到一个的情况,但如上所示,它是可能的。