首先我想澄清一下,我不是在问什么是“迭代器”。
这就是 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 at0
).
这清楚地表明,虽然两种协议(protocol)都使对象可迭代,但只有一个是实际的“迭代协议(protocol)”,而 isinstance(thing, Iterable)
正是这个协议(protocol)。测试.因此,我们可以得出结论,在最常见的情况下检查“可以迭代的事物”的一种方法是:
isinstance(thing, (Iterable, Sequence))
尽管这也需要您实现 __len__
以及__getitem__
到“虚拟子类” Sequence
.
关于python - "iterable"在Python中到底意味着什么?为什么我的实现 `__getitem__()` 的对象不是可迭代的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32799980/