检测对象是否可重复迭代

时间:2016-11-06 02:35:35

标签: python python-3.x iterator

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来识别非重复的可迭代对象。

1 个答案:

答案 0 :(得分:5)

所有迭代器都是迭代器,但并非所有迭代器都是迭代器。

迭代的唯一requirement是它定义了一个返回迭代器的__iter__()方法:

  

需要为容器对象定义一个方法以提供迭代支持:

     

<强> container.__iter__()
  返回一个迭代器对象。

iterator必须遵循迭代器协议,它有两个要求:

  1. 它有一个__iter__()方法that returns the object itself

      

    <强> iterator.__iter__()
      返回迭代器对象本身。

  2. 它有一个__next__()方法,可以在每次调用时返回下一个项目,一旦用尽,就会引发StopIteration on every subsequent call

      

    一旦迭代器的__next__()方法引发StopIteration,它必须在后续调用中继续这样做。不遵守此属性的实现被视为已损坏。

  3. 这些要求意味着迭代器永远不会重复,并且您可以通过确认iter(obj) is objTrue来确认迭代是迭代器(因此根据定义不可重复):

    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
    >>> 
    

    我会毫不犹豫地称这样一个“伪造的迭代器”表现得很糟糕,我想不出你在野外找到一个的情况,但如上所示,它是可能的。