首先我要澄清,我不是在问什么是“iterator”。
这就是Python的doc:
中定义术语“可迭代”的方式迭代
一个能够一次返回其成员的对象。 迭代的例子包括所有序列类型(例如list,str, 和元组)和一些非序列类型,如dict,文件对象和 您使用 __ iter __()或__getitem __()定义的任何类的对象 方法。 Iterables可用于for循环和许多其他地方 需要序列的地方(zip(),map(),...)。当一个可迭代的 object作为参数传递给内置函数iter(),它 返回对象的迭代器。这个迭代器适用于一次通过 超过这组价值观。使用iterables时,通常不会 必须调用iter()或自己处理迭代器对象。该 for语句为您自动执行,创建临时 用于在循环期间保存迭代器的未命名变量。 另请参见迭代器,序列和生成器。
作为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'
现在它被认为是一个“真正的”可迭代对象,尽管它在迭代时不能产生任何东西。
我是否误解了某些内容或文档不正确?
答案 0 :(得分:2)
我认为这里的混淆点是,虽然实现__getitem__
允许你迭代一个对象,但它不是定义的接口的一部分按Iterable
。
abstract base classes允许一种形式的虚拟子类化,其中实现指定方法的类(在Iterable
的情况下,只有__iter__
)被isinstance
考虑并且issubclass
是ABCs 的子类,即使它们没有明确地继承它们。但是,它不会检查方法实现是否真正起作用,只是它是否提供。
有关详细信息,请参阅PEP-3119,其中介绍了ABCs。
使用
isinstance(e, collections.Iterable)
是最pythonic的方式 检查对象是否可迭代
我不同意;我会使用duck-typing而只是尝试迭代对象。如果对象不可迭代,则会引发TypeError
,如果您想处理不可迭代的输入,则可以在函数中捕获,或者如果不想,则允许覆盖到调用者。这完全反过来决定了对象如何决定实现迭代,并且只是在最合适的时间找出它是否存在。
要添加更多内容,我认为您引用的文档略微误导。引用iter
docs,这可能会清除这一点:
object 必须是支持迭代协议(
__iter__()
方法)的集合对象,或者它必须支持序列 protocol(带有整数参数的__getitem__()
方法 在0
)。
这清楚地表明,虽然两个协议都使对象可迭代,但只有一个是实际的"迭代协议" ,正是isinstance(thing, Iterable)
测试对于。因此,我们可以得出结论,在最常见的情况下,检查"您可以迭代的事情的一种方法是" :
isinstance(thing, (Iterable, Sequence))
虽然这也要求您实施__len__
以及__getitem__
到"虚拟子类" Sequence
。
答案 1 :(得分:0)
是可迭代的。但是,你还没有从abc.Iterable
继承,所以Python自然不会将它报告为来自该类的后代。
答案 2 :(得分:-1)
Iterable
是(收集任何东西)的东西,允许对其元素进行某种迭代。但是python中迭代的通用方法是什么?这是使用 - in
关键字,它使用对象的__iter__
方法。因此,在该术语中,定义__iter__
的任何对象都可以与in
一起使用,并且是可迭代的。
所以,大多数'鸭子式'检查一个对象是否可迭代的方法是,如果一个对象是这样的,(是的,我知道隐含的是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