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

如何在Python中检查对象是否是迭代器?,python,iterator,Python,Iterator,我可以检查next()方法,但这足够了吗?有一种表意方式吗?如果一个对象实现了迭代器协议,那么它是可编辑的。 您可以使用以下方法检查\uuuu iter\uuuu()方法的存在: hasattr(object,'__iter__') 在Python2.x中,这种方法忽略了str对象和其他内置序列类型,如unicode、xrange和buffer。它在Python3中工作 另一种方法是用iter方法进行测试: try: iter(object) except TypeError: #

我可以检查
next()
方法,但这足够了吗?有一种表意方式吗?

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

hasattr(object,'__iter__')
在Python2.x中,这种方法忽略了str对象和其他内置序列类型,如unicode、xrange和buffer。它在Python3中工作

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

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

在Python 2.6或更高版本中,用于此类行为检查的design-In习惯用法是在标准库的
collections
模块中使用抽象基类进行“成员身份检查”:

>>> import collections
>>> isinstance('ciao', collections.Iterable)
True
>>> isinstance(23, collections.Iterable)
False
>>> isinstance(xrange(23), collections.Iterable)
True
事实上,这种检查是新抽象基类的主要设计原因(第二个重要原因是提供“mixin功能”在某些情况下,这就是为什么它们是ABC而不仅仅是接口——但这不适用于
集合。Iterable
,它的存在严格允许使用
isinstance
IsubClass
)进行此类检查。ABC允许实际上并没有从它们继承的类被“注册”为子类,这样这些类就可以作为ABC的“子类”进行这样的检查;而且,它们可以在内部对特殊方法执行所有必要的检查(在本例中是
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
),因此您不必这样做

如果您一直使用较旧的Python版本,“最好请求原谅,而不是许可”:

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

请注意,对于这种特殊情况,您通常希望使用特殊的大小写字符串(这是可编辑的,但大多数应用程序上下文都希望将其视为“标量”)。无论您使用什么方法来检查可写性,如果您需要这种特殊的大小写,只需预先检查
isinstance(x,basestring)
——例如:

def reallyiterable(x):
  return not isinstance(x, basestring) and isinstance(x, collections.Iterable)

编辑:正如一篇评论中指出的那样,问题的焦点在于一个对象是否是iter***或***而不是它是否是iter***可***(所有迭代器都是iter,但并非相反——并非所有iter都是迭代器)
isinstance(x,collections.Iterator)
是一种非常类似的方法,可以专门检查该条件。

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

  • obj
    有一个
    方法
  • obj
    有一个
    next
    方法(或Python 3中的
    \uuuuuuuuuuuuuuuuuuuuuuuuuuuu
  • obj.\uuu iter\uuu()
    返回
    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源代码文档注释的答案:

{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.

因为问题是关于迭代器不可迭代的,考虑迭代器的使用,这是一种最简单的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()应该足够了

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

在Python中,我们有两种东西:
Iterable
Iterator
。如果对象可以为您提供迭代器,则该对象是可伸缩的。当您在其上使用
iter()
时,它会这样做。如果可以使用
next()
顺序浏览其元素,则对象是
Iterator
。例如,
map()

给你

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

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》一书,并在本文中进行了说明

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

>>> list_iter = iter([])
>>> iter(list_iter) is list_iter
True
from collections.abc导入迭代器
isinstance(对象、迭代器)

这些问题询问对象是否是迭代器,而不是是否可迭代。因此,您应该使用collections.Iterator而不是collections.IterableIn Python 3.8及更高版本,看起来像
collections.Iterator
将改为
collections.abc.Iterator
。Python3.7对此发出了一个弃用警告:“从“collections”而不是从“collections.abc”使用或导入abc是弃用的,在3.8中它将停止工作”。迭代器和iterable不是一回事<代码>[]
是可iterable,但它不是迭代器。创建迭代器可能很昂贵,而检查属性是否存在总是很快。这将检查对象是否可iterable,而不是它是否是迭代器将调用
obj.\uuuuuuuuuuuuuu
冒着更改某些东西的风险?@BobStein VisiBone:只有当对象有bug时才这样做。@EthanFurman你什么意思?如果
obj
是一个迭代器,那么是的,它不应该改变什么。但是如果
obj
不是迭代器,
obj.\uuuu iter\uuuu()
可以有副作用。@PyRulez:大概BobStein的问题是关于迭代器的,我的答案肯定是关于迭代器的;如果所讨论的
obj
实际上不是迭代器,那么我对他的回答就不适用了。@EthanFurman,嗯?这难道不意味着你就可以返回true吗?这就改进了现有的答案如何?虽然这段代码可以解决这个问题,但如何以及为什么解决这个问题将真正有助于提高你的帖子质量,并可能导致更多的投票。请记住,你是在将来回答读者的问题,而不仅仅是现在提问的人。请在你的答案中添加解释,并指出哪些限制和假设适用。如果足够,也太多了!使用next()可以推进迭代器。正在丢弃数据以进行类型检查!这在现实世界的用例中是不可靠的。@Zim因为OP提到过,他们可以使用next()方法,我不认为这是个问题。例如,我可以尝试根据错误消息进行迭代,如果它不是迭代器,那么我可能有处理不同数据类型的逻辑。所以这完全取决于你的需要。你能详细描述一下你的真实世界用例吗
>>> list_iter = iter([])
>>> iter(list_iter) is list_iter
True