如何检查一个对象是否是 Python 中的迭代器?
问题描述
我可以检查 next()
方法,但这是否足够?有没有意识形态的方式?
I can check for a next()
method, but is that enough? Is there an ideomatic way?
解决方案
在 Python 2.6 或更高版本中,用于此类行为检查的内置习惯用法是在 collections<中使用抽象基类的成员检查"/code> 标准库模块:
In Python 2.6 or better, the designed-in idiom for such behavioral checks is a "membership check" with the abstract base class in the collections
module of the standard library:
>>> import collections
>>> isinstance('ciao', collections.Iterable)
True
>>> isinstance(23, collections.Iterable)
False
>>> isinstance(xrange(23), collections.Iterable)
True
确实,这种检查是新抽象基类的主要设计原因(第二个重要的原因是在某些情况下提供混合功能",这就是为什么它们是 ABC 而不仅仅是接口 - 但是不适用于 collections.Iterable
,它存在 严格 以允许使用 isinstance
或 issubclass
进行此类检查).ABC 允许实际上不从它们继承的类被注册"为子类,以便此类检查可以成为 ABC 的子类";并且,它们可以在内部对特殊方法(在本例中为 __iter__
)执行所有需要的检查,因此您不必这样做.
Indeed, this kind of checks is the prime design reason for the new abstract base classes (a second important one is to provide "mixin functionality" in some cases, which is why they're ABCs rather than just interfaces -- but that doesn't apply to collections.Iterable
, it exists strictly to allow such checks with isinstance
or issubclass
). ABCs allow classes that don't actually inherit from them to be "registered" as subclasses anyway, so that such classes can be "subclasses" of the ABC for such checks; and, they can internally perform all needed checks for special methods (__iter__
in this case), so you don't have to.
如果您被旧版本的 Python 卡住了,请求宽恕比请求许可要好":
If you're stuck with older releases of Python, "it's better to ask forgiveness than permission":
def isiterable(x):
try: iter(x)
except TypeError: return False
else: return True
但这不像新方法那样快速和简洁.
but that's not as fast and concise as the new approach.
请注意,对于这种特殊情况,您通常需要特殊情况的字符串(它们是可迭代的,但大多数应用程序上下文都希望将其视为标量").无论您使用哪种方法来检查可迭代性,如果您需要这种特殊的大小写,只需预先检查 isinstance(x, basestring)
- 例如:
Note that for this special case you'll often want to special-case strings (which are iterable but most application contexts want to treat as "scalars" anyway). Whatever approach you're using to check iterableness, if you need such special casing just prepend a check for isinstance(x, basestring)
-- for example:
def reallyiterable(x):
return not isinstance(x, basestring) and isinstance(x, collections.Iterable)
编辑:正如评论中指出的那样,问题集中在对象是否是迭代器***而不是它是否可迭代***(所有迭代器是可迭代的,但反之亦然——并非所有可迭代对象都是迭代器).isinstance(x, collections.Iterator)
是专门检查该条件的完全类似的方法.
Edit: as pointed out in a comment, the question focuses on whether an object is an iter***ator*** rather than whether it's iter***able*** (all iterators are iterable, but not vice versa -- not all iterables are iterators). isinstance(x, collections.Iterator)
is the perfectly analogous way to check for that condition specifically.
相关文章