【问题标题】:Is an iterator also an iterable?迭代器也是可迭代的吗?
【发布时间】:2018-02-16 18:28:57
【问题描述】:

我发现:

>>> a={'x':42, 'y':3.14, 'z':7}
>>> b=a.__iter__()
>>> b.__dir__()
['__next__', ..., '__iter__', ...]
>>> b
<set_iterator object at 0x7efdd4e5afc0>

迭代器总是有__iter__ 方法吗?

根据https://stackoverflow.com/a/9884259,一个迭代器也是一个可迭代对象。如果迭代器总是有__iter__ 方法是真的?

【问题讨论】:

  • 是的,它总是这样。它应该返回self
  • 说真的,请查看this gist。我认为它应该消除一些关于 for 循环、什么是迭代器以及什么是可迭代的混淆。
  • 我认为值得注意的是,有时人们关于迭代器和可迭代对象的语言与实际协议细节相反。也就是说,如果有人说“X 是可迭代的”,他们可能打算排除迭代器(尽管迭代器总是具有 __iter__ 方法,因此在官方意义上是可迭代的)。 “非迭代器可迭代”没有好的单字术语,所以有些人只是使用“可迭代”来表示,即使它不准确。我在a previous answer 中详细阐述了这个主题。

标签: python python-3.x methods iterator iterable


【解决方案1】:

迭代器是可迭代的。

这是记录和解释here

迭代器必须有一个返回迭代器对象本身的__iter__() 方法,所以每个迭代器也是可迭代的

可迭代对象不一定是迭代器

根据定义,迭代器必须具有__next__ 方法。举个简单的反例:

>>> ''.__next__
AttributeError: 'str' object has no attribute '__next__'

字符串对象是可迭代对象,但不是迭代器。

【讨论】:

  • 谢谢。 “字符串对象是可迭代的,但不是迭代器。”但'abc'.__iter__ 存在且'abc' 是字符串对象。我错过了什么吗?
  • 迭代器在调用__iter__ 时返回自己。但是字符串返回一个string_iterator 对象。所以它是可迭代的,但不是迭代器(它没有返回自己)。
  • @MSeifert string_iterator 对象不是迭代器吗?
  • @Ben 因为要成为一个迭代器,它需要一个__next__ 方法
  • @juanpa.arrivillaga 不,他们真的是班级。试试看:map.__iter__map.__next__。我不是说openiter 是迭代器。这两个是真正的返回迭代器的工厂函数。
【解决方案2】:

迭代器是否总是有 __iter__ 方法?

是的。所有迭代器都有一个返回自身的__iter__ 方法。来自docs

iterator.__iter__()

返回迭代器对象本身。这是 需要允许容器和迭代器与 for 和 in 语句。

【讨论】:

    【解决方案3】:

    迭代器是可迭代的。是的,迭代器总是有一个__iter__ 方法。

    在调用__iter__钩子的迭代器上调用iter,返回相同的迭代器:

    >>> it = iter([]) # return iterator from iterable
    >>> it is iter(iter(it)) is it.__iter__().__iter__().__iter__()
    True
    

    method chaining 的经典例子。

    您一定也注意到了,自定义类的迭代器协议的大多数实现始终遵循:

    def __iter__(self):
        return self
    

    也就是说,如果迭代没有通过return iter(...) 委托给另一个迭代器。

    迭代器 不实现iterator protocol 是非常违反直觉的,你不觉得吗?协议的__iter__实现描述如下:

    iterator.__iter__()
    

    返回迭代器对象本身。这需要同时允许 与forin 语句一起使用的容器和迭代器。

    [强调我的]

    此行为预期与内置函数返回的迭代器对象一致:

    >>> m = map(None, [])
    >>> m
    <map object at 0x...>
    >>> m is m.__iter__().__iter__().__iter__()
    True
    

    P.S:我很抱歉一再打电话给dunders;让它看起来是正确的做法。 But it's not!

    【讨论】:

    • 没有。迭代器可以有 __getitem__ 而不是 __iter__ 所以这不是真的。
    • 不,您正在考虑“可迭代”。 “迭代器”总是有一个__iter__ 方法。
    • 这是允许容器和迭代器与 for 和 in 语句一起使用所必需的 __contains__,然后__iter__不需要in语句的右侧使用它。
    • @wim 我认为它们的意思是 for 循环语法:for ... in ... 与“forin”。实际上不是in,如contains
    • 我对此表示怀疑。循环在语法中只是称为“for 语句”。那个文本是from 16 years ago (!),所以其目的可能是通过迭代来描述旧式的成员资格测试。否则,没有充分的理由将“forin 语句”明确写成两个不同的语句。
    【解决方案4】:

    一个可迭代对象需要实现一个__iter__ method or a __getitem__ method

    如果对象实现了__iter__()__getitem__(),则可以使用for 对其进行迭代。

    迭代器需要__iter__ 方法(返回self)和__next__ 方法(我不能100% 确定__next__)。

    迭代器总是有__iter__方法是真的吗?

    是的!

    这也记录在Data model:

    object.__iter__(self)

    当容器需要迭代器时调用此方法。此方法应返回一个新的迭代器对象,该对象可以迭代容器中的所有对象。对于映射,它应该遍历容器的键。

    迭代器对象也需要实现这个方法;他们必须自己返回。有关迭代器对象的更多信息,请参阅迭代器类型。

    (强调我的)

    关于你的第二个问题:

    迭代器也是可迭代的吗?

    是的,因为它有一个__iter__ 方法。

    补充说明

    除了正式实现之外,只需检查是否可以在其上调用 iter() 即可轻松检查某些内容是否可迭代:

    def is_iterable(something):
        try:
            iter(something)
        except TypeError:
            return False
        else:
            return True
    

    同样,可以通过检查 iter() 调用某事物是否返回自身来检查某事物是否为迭代器:

    def is_iterator(something):
        try:
            return iter(something) is something  # it needs to return itself to be an iterator
        except TypeError:
            return False
    

    但不要在开发代码中使用它们,这些只是为了“可视化”。大多数情况下,您只需使用for ... in ... 对某些内容进行迭代,或者如果您需要使用iterator = iter(...) 的迭代器,然后通过调用next(iterator) 处理迭代器,直到它抛出StopIteration

    【讨论】:

    • 谢谢。我可以找到哪个参考“可迭代具有 iter 方法或 getitemlen 方法”?那些没有__iter__ 的迭代器是什么?
    • @Ben 我添加了一些链接 :)
    • 谢谢。没有__iter__ 的内置可迭代对象是什么?
    • 我认为没有。这主要用于用户定义的类似序列的迭代。
    • @Ben:在 Python 2 中,str 没有__iter__。我不知道 Python 3 上有任何没有 __iter__ 的内置可迭代类型。
    猜你喜欢
    • 2012-12-13
    • 2019-11-21
    • 2021-08-24
    • 2020-01-21
    • 2019-07-05
    • 2020-06-29
    • 2018-07-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多