如何检查对象是否是Python中的迭代器?

时间:2010-06-11 14:16:06

标签: python iterator

我可以查看next()方法,但这还够吗?有没有一种思想方式?

8 个答案:

答案 0 :(得分:52)

在Python 2.6或更高版本中,这种行为检查的设计用语是对标准库的collections模块中的抽象基类进行“成员资格检查”:

>>> import collections
>>> isinstance('ciao', collections.Iterable)
True
>>> isinstance(23, collections.Iterable)
False
>>> isinstance(xrange(23), collections.Iterable)
True

实际上,这种检查是新抽象基类的主要设计原因(第二个重要的是在某些情况下提供“mixin功能”,这就是为什么它们是ABCs而不仅仅是接口 - 但是这不适用于collections.Iterable严格以允许使用isinstanceissubclass进行此类检查。 ABCs允许实际上不从它们继承的类被“注册”为子类,因此这些类可以是ABC的“子类”以进行此类检查;并且,他们可以在内部执行特殊方法的所有必要检查(在这种情况下为__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)是完全类似的方式来检查这种情况。

答案 1 :(得分:15)

如果对象实现了迭代器协议,则该对象是可迭代的 您可以使用以下方法检查__iter__()方法是否存在

hasattr(object,'__iter__')
在Python 2.x中,

这种方法错过了str对象和其他内置序列类型,如unicode,xrange,buffer。它适用于Python 3。

另一种方法是用iter方法测试它:

try:
   iter(object)
except TypeError:
   #not iterable

答案 2 :(得分:6)

要成为迭代器,对象必须通过三次测试:

  • obj有一个__iter__方法
  • objnext方法(或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

答案 3 :(得分:0)

来自python源代码文档注释的答案:

{python安装路径} /Versions/3.5/lib/python3.5/types.py

# Iterators in Python aren't a matter of type but of protocol.  A large
# and changing number of builtin types implement *some* flavor of
# iterator.  Don't check the type!  Use hasattr to check for both
# "__iter__" and "__next__" attributes instead.

答案 4 :(得分:0)

由于问题是关于迭代器不可迭代,并考虑使用迭代器,这是一种最简单,最Python化的方法

iterable = [1,2]
iterator = iter(iterable)


def isIterator(obj):
    try:
        next(obj, None)
        return True
    except TypeError:
        return False

>>> isIterator(iterable)
False
>>> isIterator(iterator)
True

是的。检查next()应该足够

答案 5 :(得分:0)

有比其他答案建议的更好的方法。

在Python中,我们有两种东西:IterableIterator。如果对象可以给您Iterable,则它是Iterator。当您在其上使用iter()时,它会这样做。如果可以使用Iterator顺序浏览其元素,则该对象为next()。例如,map()返回Iterator,而listIterable

这里是more details

下面的代码说明了如何检查这些类型:

from collections.abc import Iterable, Iterator

r = [1, 2, 3]
e = map(lambda x:x, r)

print(isinstance(r, Iterator)) # False, because can't apply next
print(isinstance(e, Iterator)) # True
print(isinstance(r, Iterable)) # True, because can apply iter()
print(isinstance(e, Iterable)) # True, note iter() returns self

答案 6 :(得分:0)

此示例来自 Effective Python 一书,并在此post中进行了说明。

  

一个Iterable产生一个迭代器。任何迭代器也是可迭代的   但将其自身作为迭代器:

>>> list_iter = iter([])
>>> iter(list_iter) is list_iter
True

答案 7 :(得分:0)

from collections.abc import Iterator

isinstance(object, Iterator)