如何检查一个对象是否是Python中的迭代器?
我可以检查一下有没有一个 next()
方法,但这样就够了吗?有没有更合适的做法呢?
10 个回答
要成为一个迭代器,一个对象必须通过三个测试:
obj
必须有一个__iter__
方法obj
必须有一个next
方法(在 Python 3 中是__next__
)obj.__iter__()
必须返回obj
本身
所以,自己测试的代码大概是这样的:
def is_iterator(obj):
if (
hasattr(obj, '__iter__') and
hasattr(obj, 'next') and # or __next__ in Python 3
callable(obj.__iter__) and
obj.__iter__() is obj
):
return True
else:
return False
一个对象如果能被循环遍历,就叫做可迭代对象。
你可以通过检查这个对象是否有__iter__()
这个方法来判断它是否可迭代。
hasattr(object,'__iter__')
在Python 2.x中,这种方法会漏掉一些字符串对象和其他内置的序列类型,比如unicode、xrange和buffer。但在Python 3中,这种方法是有效的。
另一种方法是使用iter方法来测试:
try:
iter(object)
except TypeError:
#not iterable
在Python 2.6或更新的版本中,进行这种行为检查的一个常用方法是使用标准库中collections
模块的抽象基类进行“成员检查”。
>>> import collections
>>> isinstance('ciao', collections.Iterable)
True
>>> isinstance(23, collections.Iterable)
False
>>> isinstance(xrange(23), collections.Iterable)
True
实际上,这种检查的主要设计原因就是为了引入新的抽象基类(还有一个重要原因是提供“混入功能”,这就是为什么它们是抽象基类而不仅仅是接口——不过这不适用于collections.Iterable
,它的存在是为了允许使用isinstance
或issubclass
进行这样的检查)。抽象基类允许那些并不直接继承它们的类也能被“注册”为子类,这样这些类就可以在进行检查时被视为抽象基类的“子类”;而且,它们可以内部执行所有需要的特殊方法检查(在这个例子中是__iter__
),所以你不需要自己去做。
如果你还在使用旧版本的Python,“与其请求许可,不如事后求情”:
def isiterable(x):
try: iter(x)
except TypeError: return False
else: return True
但这种方法没有新方法那么快速和简洁。
注意,对于这个特殊情况,你通常会想要特别处理字符串(字符串是可迭代的,但在大多数应用场景中希望将其视为“标量”)。无论你使用什么方法来检查是否可迭代,如果需要这种特殊处理,只需在前面加一个isinstance(x, basestring)
的检查——例如:
def reallyiterable(x):
return not isinstance(x, basestring) and isinstance(x, collections.Iterable)
编辑:正如评论中指出的,问题关注的是一个对象是否是迭代器,而不是它是否可迭代(所有迭代器都是可迭代的,但反之不成立——并不是所有可迭代的对象都是迭代器)。isinstance(x, collections.Iterator)
是检查这个条件的完美方法。