“究竟是什么?”;iterable“;用Python是什么意思?为什么不是';我的对象实现了一个iterable`\uuuu getitem\uuu()`吗?

“究竟是什么?”;iterable“;用Python是什么意思?为什么不是';我的对象实现了一个iterable`\uuuu getitem\uuu()`吗?,python,iterable,Python,Iterable,首先我想澄清一下,我不是在问什么是“迭代器” 这就是术语“iterable”在Python中的定义: iterable 能够一次返回一个成员的对象。 iterables的示例包括所有序列类型(如list、str、, 和元组)和一些非序列类型,如dict、文件对象和 使用\uuuu iter\uuuuuuuuuuuuuu()或uuuu getitem\uuuuuuuuuuuu()方法定义的任何类的对象 Iterables可用于for循环和许多其他地方 需要序列的位置(zip(),map(),…)。

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

这就是术语“iterable”在Python中的定义:

iterable

能够一次返回一个成员的对象。 iterables的示例包括所有序列类型(如list、str、, 和元组)和一些非序列类型,如dict、文件对象和 使用\uuuu iter\uuuuuuuuuuuuuu()或uuuu getitem\uuuuuuuuuuuu()方法定义的任何类的对象

Iterables可用于for循环和许多其他地方 需要序列的位置(zip(),map(),…)。当一个不可忍受的人 对象作为参数传递给内置函数iter(),它 返回对象的迭代器。这个迭代器适合一次遍历 在一组值上。当使用iterables时,通常不是 需要调用iter()或自己处理迭代器对象。这个 for语句会自动为您创建一个临时 未命名变量,用于在循环期间保持迭代器

另请参见迭代器、序列和生成器

例如,使用
isinstance(e,collections.Iterable)
是检查对象是否可Iterable的最具python风格的方法。
所以我用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
定义了
\uuu getitem\uuuu
方法,但它不被视为一个iterable对象,更不用说它能够一次返回一个数字了

然后,我删除了
\uuu getitem\uuuuuuuuuuu
并添加了
\uuuuuuu iter\uuuuuuuuuu
方法:

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'
它现在被认为是一个“真正的”可编辑对象,尽管它在迭代时不能生成任何内容


那么,我是否误解了某些内容,或者文档不正确?

这是一个可编辑的文档。但是,您没有从abc.Iterable继承,因此Python自然不会将其报告为该类的后代。这两件事——作为一个iterable和从基类下降——是完全不同的。

iterable
是允许对其元素进行某种迭代的东西(集合任何东西)。但是python中迭代的一般方式是什么?这就是在关键字中使用-
,它使用对象的方法。因此,在这方面,任何定义
的对象都可以与
中的
一起使用,并且是一个Iterable

因此,检查对象是否可iterable的大多数“duck-typing”方法是检查对象是否为this(是的,我隐式地知道,由于虚拟类的缘故,
isinstance
案例中也发生了这种情况)

因为根据duck类型,我们关心的是对象提供的行为,而不是它的故事

如果您的
\uuuu iter\uuuu
实现有错误,这并不意味着对象不可编辑,这只意味着您的代码中有错误

注意:-那些没有定义
\uuu iter\uuuu
的对象在一般意义上仍然是可移植的,通过使用其他方法,只是它们不能与
关键字中的
一起使用。
例如:-
NumberList
实例在
每个方法上都是可iterable的,但在python意义上是不可iterable的

class NumberList:

     def __init__(self, values):
         self.values = values

     def each(self):
         return self.values

我认为这里的混淆点在于,尽管实现
\uuuu getitem\uuuu
允许您迭代对象,但它不是由定义的接口的一部分

允许一种形式的虚拟子类化,
isinstance
issubclass
认为实现指定方法的类(在
Iterable
的情况下,只有
\uu iter\uuuu
)是ABC的子类,即使它们没有显式地从ABC继承。不过,它并不检查方法实现是否实际工作,只检查是否提供了方法实现

有关更多信息,请参阅,其中介绍了ABCs


使用
isinstance(e,collections.Iterable)
是最具python风格的方法 检查对象是否可编辑的步骤

我不同意;我将使用并尝试在对象上迭代。如果对象不可iterable,将引发
TypeError
,如果要处理不可iterable的输入,可以在函数中捕获该错误,如果不可iterable,则允许向调用方渗透。这完全回避了对象决定如何实现迭代的步骤,只是找出它是否在最合适的时间实现迭代


再补充一点,我认为你引用的文件有点误导。引用这句话,或许可以澄清这一点:

对象必须是支持迭代协议的集合对象(方法
\uu iter\uu()
),或者它必须支持序列 协议(带有整数参数的
\uuuu getitem\uuuu()方法
在
0

这清楚地表明,尽管两个协议都使对象可移植,但只有一个协议是实际的“迭代协议”,并且正是这一点,
isinstance(thing,iterable)
测试了它。因此,我们可以得出结论,在最普遍的情况下,检查“您可以迭代的内容”的一种方法是:

isinstance(thing, (Iterable, Sequence))

虽然这也要求您将
\uuu len\uuuuuuuuuuuuuuuuuuuuu
\uuuuu getitem\uuuuuuuuuuuuuuuu
一起实现到“虚拟子类”
序列

isinstance
将无法检查接口是否正确实现,但在您实际尝试对其进行迭代之前,这一点不会被发现,只是需要使用适当的方法(在本例中)是可用的。“使用
isinstance(e,collections.Iterable)
是检查对象是否可Iterable的最具python风格的方法”-不,我想说尝试对其进行迭代是最具python风格的方法!要测试某个对象是否可Iterable,我需要执行一个try/except块,其中我尝试var=iter(var),如果它抛出和异常,则它不是iterable@jonrsharpe.但那
isinstance(thing, (Iterable, Sequence))