繁体   English   中英

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

[英]How can I check if an object is an iterator in Python?

我可以检查next()方法,但这是否足够? 有没有意识形态的方法?

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

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

事实上,这种检查是新抽象基类的主要设计原因(第二个重要的原因是在某些情况下提供“混合功能”,这就是为什么它们是 ABC 而不仅仅是接口——但这不是t 适用于collections.Iterable ,它严格存在以允许使用isinstanceissubclass进行此类检查)。 ABC 允许实际上并不从它们继承的类无论如何“注册”为子类,以便此类类可以是 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)是专门检查该条件的完全类似的方法。

如果一个对象实现了迭代器协议,那么它就是可迭代的。
您可以使用以下方法检查__iter__()方法的存在:

hasattr(object,'__iter__')

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

另一种方法是使用 iter 方法对其进行测试:

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

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

  • 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

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

在 Python 中,我们有两种东西: IterableIterator 如果一个对象可以给你Iterator它就是Iterable 当您在其上使用iter()时它iter() 如果您可以使用next()顺序浏览其元素,则该对象是Iterator 例如, map()返回Iterator并且listIterable

这里有更多细节

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

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

来自 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.
from collections.abc import Iterator

isinstance(object, Iterator)

如果您想检查该值是否可迭代,您可以执行以下操作:

>>> from typing import Iterable

>>> isinstance([], Iterable)
True
>>> isinstance(1, Iterable)
False

如果您想检查它是否是迭代器,您可以执行以下操作:

>>> hasattr(obj, "__iter__") and hasattr(obj, "__next__")
True

这个例子来自《 Effective Python 》一书,并在这篇文章中进行了说明。

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

 >>> list_iter = iter([]) >>> iter(list_iter) is list_iter True
if '__iter__' in dir(object):
   #code
else:
   #code

由于问题是关于 Iterator not Iterable 并考虑使用 iterator,这是一种最简单的 Pythonic 方法

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() 应该就足够了

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM