"iterable" 在 Python 中到底是什么意思?为什么我实现了“__getitem__()”的对象不是可迭代对象?
What exactly does "iterable" mean in Python? Why isn't my object which implements `__getitem__()` an iterable?
首先我想澄清一下,我不是在问什么是 "iterator"。
这就是术语 "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'
它现在被认为是一个 "true" 可迭代对象,尽管它在迭代时不能产生任何东西。
我是不是误解了什么或者文档不正确?
它是一个可迭代对象。但是,您没有继承自 abc.Iterable
,因此 Python 自然不会将其报告为 class 的后代。这两件事 - 作为一个可迭代的,并且从那个基础 class 下降 - 是完全分开的。
Iterable
是允许对其元素进行某种迭代的东西(集合任何东西)。但是 python 中的通用迭代方式是什么?即使用-in
关键字,即使用对象的__iter__
方法。因此,在这个术语中,任何定义 __iter__
的对象都可以与 in
一起使用,并且是一个 Iterable。
所以,大多数 'duck-typish' 检查对象是否可迭代的方法是对象是否是这个,(是的,我隐含地知道这也是 isinstance
情况下发生的事情,由于虚拟 类)
hasattr(train, '__iter__')
因为根据鸭子类型,我们关心对象提供的行为而不是它的祖先。
如果您的 __iter__
实现有误,这并不意味着对象不可迭代,它只是意味着您的代码中存在错误。
注意:- 那些没有定义 __iter__
的对象在一般意义上仍然可以迭代,通过使用其他方法,只是它们不能与 in
关键字一起使用。
例如:- NumberList
实例可通过 each
方法迭代,但在 python 意义上不可迭代。
class NumberList:
def __init__(self, values):
self.values = values
def each(self):
return self.values
我认为这里的混淆点是,尽管实现 __getitem__
确实 允许您迭代一个对象,但 不是Iterable
定义的接口的一部分。
abstract base classes 允许一种形式的虚拟子类化,其中 类 实现了指定的方法(在 [=12= 的情况下,只有 __iter__
)被考虑isinstance
和 issubclass
是 ABC 的子类,即使它们没有明确继承它们。它不检查方法实现 是否实际工作 ,只是检查它是否被提供。
有关详细信息,请参阅介绍 ABC 的 PEP-3119。
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
).
这清楚地表明,尽管两种协议都使对象可迭代,但只有一个是实际的 "iteration protocol",也就是 isinstance(thing, Iterable)
测试。因此我们可以得出结论,在大多数情况下检查 "things you can iterate over" 的一种方法是:
isinstance(thing, (Iterable, Sequence))
虽然这也需要您实现 __len__
以及 __getitem__
到 "virtually sub-class" Sequence
.
首先我想澄清一下,我不是在问什么是 "iterator"。
这就是术语 "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'
它现在被认为是一个 "true" 可迭代对象,尽管它在迭代时不能产生任何东西。
我是不是误解了什么或者文档不正确?
它是一个可迭代对象。但是,您没有继承自 abc.Iterable
,因此 Python 自然不会将其报告为 class 的后代。这两件事 - 作为一个可迭代的,并且从那个基础 class 下降 - 是完全分开的。
Iterable
是允许对其元素进行某种迭代的东西(集合任何东西)。但是 python 中的通用迭代方式是什么?即使用-in
关键字,即使用对象的__iter__
方法。因此,在这个术语中,任何定义 __iter__
的对象都可以与 in
一起使用,并且是一个 Iterable。
所以,大多数 'duck-typish' 检查对象是否可迭代的方法是对象是否是这个,(是的,我隐含地知道这也是 isinstance
情况下发生的事情,由于虚拟 类)
hasattr(train, '__iter__')
因为根据鸭子类型,我们关心对象提供的行为而不是它的祖先。
如果您的 __iter__
实现有误,这并不意味着对象不可迭代,它只是意味着您的代码中存在错误。
注意:- 那些没有定义 __iter__
的对象在一般意义上仍然可以迭代,通过使用其他方法,只是它们不能与 in
关键字一起使用。
例如:- NumberList
实例可通过 each
方法迭代,但在 python 意义上不可迭代。
class NumberList:
def __init__(self, values):
self.values = values
def each(self):
return self.values
我认为这里的混淆点是,尽管实现 __getitem__
确实 允许您迭代一个对象,但 不是Iterable
定义的接口的一部分。
abstract base classes 允许一种形式的虚拟子类化,其中 类 实现了指定的方法(在 [=12= 的情况下,只有 __iter__
)被考虑isinstance
和 issubclass
是 ABC 的子类,即使它们没有明确继承它们。它不检查方法实现 是否实际工作 ,只是检查它是否被提供。
有关详细信息,请参阅介绍 ABC 的 PEP-3119。
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 at0
).
这清楚地表明,尽管两种协议都使对象可迭代,但只有一个是实际的 "iteration protocol",也就是 isinstance(thing, Iterable)
测试。因此我们可以得出结论,在大多数情况下检查 "things you can iterate over" 的一种方法是:
isinstance(thing, (Iterable, Sequence))
虽然这也需要您实现 __len__
以及 __getitem__
到 "virtually sub-class" Sequence
.