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

Jua*_*nti 38 python iterator

我可以检查一下next()方法,但这还够吗?有一种意识形态的方式吗?

Ale*_*lli 56

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

>>> import collections
>>> isinstance('ciao', collections.Iterable)
True
>>> isinstance(23, collections.Iterable)
False
>>> isinstance(xrange(23), collections.Iterable)
True
Run Code Online (Sandbox Code Playgroud)

实际上,这种检查是新抽象基类的主要设计原因(第二个重要的是在某些情况下提供"mixin功能",这就是为什么它们是ABCs而不仅仅是接口 - 但这并不是'适用于collections.Iterable,它严格存在以允许与isinstanceor issubclass)进行此类检查.ABCs允许实际上不从它们继承的类被"注册"为子类,因此这些类可以是ABC的"子类"以进行此类检查; 并且,他们可以在内部执行特殊方法所需的所有检查(__iter__在这种情况下),因此您不必这样做.

如果你坚持使用旧版本的Python,"请求宽恕而不是许可":

def isiterable(x):
  try: iter(x)
  except TypeError: return False
  else: return True
Run Code Online (Sandbox Code Playgroud)

但这并不像新方法那么快速和简洁.

请注意,对于这种特殊情况,您通常需要特殊情况字符串(可迭代,但大多数应用程序上下文仍然希望将其视为"标量").无论您使用什么方法来检查可迭代性,如果您需要这样的特殊套管,只需要预先检查isinstance(x, basestring)- 例如:

def reallyiterable(x):
  return not isinstance(x, basestring) and isinstance(x, collections.Iterable)
Run Code Online (Sandbox Code Playgroud)

编辑:正如评论中指出的那样,问题集中在一个对象是否是一个对象***而不是它是否为*********(所有迭代器都是可迭代的,但反之亦然 -并非所有迭代都是迭代器). isinstance(x, collections.Iterator)是特别检查这种情况的完全类似的方法.

  • 这些问题询问对象是否是迭代器,而不是它是否可迭代.所以你应该使用collections.Iterator而不是collections.Iterable (17认同)
  • 在Python 3.8及更高版本中,看起来像`collections.Iterator`将会是`collections.abc.Iterator`。Python 3.7为此发出了弃用警告:“已弃用从'collections'而不是'collections.abc'使用或导入ABC,在3.8中它将停止工作。 (2认同)
  • 迭代器和可迭代不是一回事。`[]` 是可迭代的,但它不是迭代器。 (2认同)

sys*_*out 16

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

hasattr(object,'__iter__')
Run Code Online (Sandbox Code Playgroud)

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

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

try:
   iter(object)
except TypeError:
   #not iterable
Run Code Online (Sandbox Code Playgroud)

  • 这将检查对象是否为* iterable *,而不是是否为* iterator * (4认同)
  • 创建迭代器可能很昂贵,而检查属性是否存在总是*快*。 (2认同)

Shi*_*hah 9

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

在 Python 中,我们有两种东西:IterableIterator。一个物体就是Iterable它能给你的Iteratoriter()当你使用它时它会这样做。一个对象就是Iterator您可以用来next()顺序浏览其元素的对象。例如,map()返回Iteratorlistis Iterable

以下是更多详细信息

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

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
Run Code Online (Sandbox Code Playgroud)


Eth*_*man 6

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

  • obj有一个__iter__方法
  • obj有一个next方法(或__next__在Python 3中)
  • 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
Run Code Online (Sandbox Code Playgroud)


小智 6

from collections.abc import Iterator

isinstance(object, Iterator)
Run Code Online (Sandbox Code Playgroud)

  • 虽然此代码可以解决问题,但[包括解释](//meta.stackexchange.com/q/114762) 如何以及为何解决问题确实有助于提高帖子的质量,并可能会带来更多结果赞成票。请记住,您是在为将来的读者回答问题,而不仅仅是现在提问的人。请[编辑]您的答案以添加解释并指出适用的限制和假设。 (4认同)