python - "iterable"在Python中到底意味着什么?为什么我的实现 `__getitem__()` 的对象不是可迭代的?

标签 python iterable

首先我想澄清一下,我不是在问什么是“迭代器”。

这就是 Python doc 中术语“可迭代”的定义。 :

iterable

An object capable of returning its members one at a time. Examples of iterables include all sequence types (such as list, str, and tuple) and some non-sequence types like dict, file objects, and objects of any classes you define with an __iter__() or __getitem__() method.

Iterables can be used in a for loop and in many other places where a sequence is needed (zip(), map(), ...). When an iterable object is passed as an argument to the built-in function iter(), it returns an iterator for the object. This iterator is good for one pass over the set of values. When using iterables, it is usually not necessary to call iter() or deal with iterator objects yourself. The for statement does that automatically for you, creating a temporary unnamed variable to hold the iterator for the duration of the loop.

See also iterator, sequence, and generator.

other people suggested ,使用 isinstance(e, collections.Iterable) 是检查对象是否可迭代的最 Pythonic 方法。
所以我用Python 3.4.3做了一些测试:

from collections.abc import Iterable

class MyTrain:
    def __getitem__(self, index):
        if index > 3:
            raise IndexError("that's enough!")

        return index

for name in MyTrain():
    print(name)  # 0, 1, 2, 3

print(isinstance(MyTrain(), Iterable))  # False

结果很奇怪:MyTrain定义了__getitem__方法,但它不被视为可迭代对象,更不用说它能够每次返回一个数字时间。

然后我删除了 __getitem__ 并添加了 __iter__ 方法:

from collections.abc import Iterable

class MyTrain:    
    def __iter__(self):
        print("__iter__ called")
        pass

print(isinstance(MyTrain(), Iterable))  # True

for name in MyTrain():
    print(name)  # TypeError: iter() returned non-iterator of type 'NoneType'

它现在被认为是一个“真正的”可迭代对象,尽管它在迭代时不能产生任何东西。

那么我是否误解了什么或者文档不正确?

最佳答案

我认为这里的困惑点在于,尽管实现 __getitem__ 允许迭代对象,它不是 Iterable 定义的接口(interface)的一部分

abstract base classes允许某种形式的虚拟子类化,其中实现指定方法的类(在 Iterable 的情况下,仅 __iter__ )被 isinstance 考虑和issubclass成为 ABC 的子类,即使它们没有显式继承自 ABC。不过,它不会检查方法实现是否实际上有效,而只是检查是否提供了该方法。

有关详细信息,请参阅 PEP-3119 ,其中介绍了 ABC。

<小时/>

using isinstance(e, collections.Iterable) is the most pythonic way to check if an object is iterable

我不同意;我会使用 duck-typing然后尝试迭代该对象。如果对象不可迭代,则 TypeError会被引发,如果你想处理不可迭代的输入,你可以在你的函数中捕获它,或者如果不想处理,则允许渗透到调用者。这完全回避了对象如何决定实现迭代,而只是找出它是否在最合适的时间执行。

<小时/>

补充一点,我认为您引用的文档稍微具有误导性。引用 iter docs ,这也许可以澄清这一点:

object must be a collection object which supports the iteration protocol (the __iter__() method), or it must support the sequence protocol (the __getitem__() method with integer arguments starting at 0).

这清楚地表明,虽然两种协议(protocol)都使对象可迭代,但只有一个是实际的“迭代协议(protocol)”,而 isinstance(thing, Iterable) 正是这个协议(protocol)。测试.因此,我们可以得出结论,在最常见的情况下检查“可以迭代的事物”的一种方法是:

isinstance(thing, (Iterable, Sequence))

尽管这也需要您实现 __len__以及__getitem__“虚拟子类” Sequence .

关于python - "iterable"在Python中到底意味着什么?为什么我的实现 `__getitem__()` 的对象不是可迭代的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32799980/

相关文章:

python - wxPython 动画 - 补间动画

javascript - 与 Javascript 类似,在 python 中构建 JSON 对象

Django过滤器 boolean 不可迭代

java - 如何打印已转换为对象的数组?

python - 如何找到第n次出现在列表中的项目的索引?

python - 如何处理 'ImportError: No module named profanity_check'

python - 字数列表无法重命名列名称

python - 将图像添加到 Tkinter Entry

java - 是否每次为Iterables调用for循环的 "condition"?

arrays - 动态 Haxe 迭代