【发布时间】:2015-09-26 17:32:02
【问题描述】:
首先我想澄清一下,我不是在问什么是“迭代器”。
这就是 Python 的 doc 中“可迭代”一词的定义方式:
可迭代
一个能够一次返回一个成员的对象。 可迭代对象的示例包括所有序列类型(例如 list、str、 和元组)和一些非序列类型,如字典、文件对象和 您使用 __iter__() 或 __getitem__() 方法定义的任何类的对象。
可迭代对象可用于 for 循环和许多其他地方 需要序列的地方(zip(),map(),...)。当一个可迭代的 对象作为参数传递给内置函数 iter(),它 返回对象的迭代器。这个迭代器适用于一次通过 超过一组值。使用可迭代对象时,通常不会 需要自己调用 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'
它现在被认为是一个“真正的”可迭代对象,尽管它在迭代时不能产生任何东西。
那么是我误解了什么还是文档不正确?
【问题讨论】:
-
isinstance不会检查接口是否正确实现,直到你真正尝试迭代它才会发现,只是适当的方法(在这种情况下only__iter__) 可用。 -
"使用
isinstance(e, collections.Iterable)是检查对象是否可迭代的最 Pythonic 方式" - 不,我会说 尝试迭代它 b> 是最 Pythonic 的方式! -
为了测试某个东西是否是可迭代的,我会在尝试 var = iter(var) 的地方执行 try / except 块,如果它抛出异常,那么它不是可迭代的
-
@jonrsharpe。但这可能会弄巧成拙,因为它可能会消耗可迭代对象。也许更好的检查是尝试
iter(x),看看它是否会引发TypeError。