isiter builtin

Chris Angelico rosuav at gmail.com
Sun Nov 16 03:14:10 EST 2014


On Sun, Nov 16, 2014 at 6:57 PM, Garrett Berg <googberg at gmail.com> wrote:
> However, there are times when I want to do type checking, and the builtin
> function isinstance is of great use. However, this function fails to be
> satisfactory in returning whether the object is a valid iterator. The call
> hasattr(obj, '__iter__') also fails because str and bytes types both have
> that, and are rarely what you mean when you are asking if something is an
> iterator (how often have you iterated over a string?)

But the correct answer is that str and bytes are both iterable. So
what you're asking is not whether something's a valid iterator, but
whether it is a non-string-iterable, which is a definitely different
thing. And that's basically what your gist is doing, although there's
a slight error in its docstring: you talk about "iterators", but
you're actually looking for "iterables".

In Python, an iterable is something which you can iterate over:
calling iter() on it will return something (rather than raising
TypeError), which means you can use it in a 'for' loop. An iterator is
an iterable which, when you call iter() on it, returns *itself*.
Normally, you get an iterator by calling iter() on something iterable,
if that makes sense. For example:

>>> iter([1,2,3,4])
<list_iterator object at 0x7f2908ec0978>
>>> iter(_)
<list_iterator object at 0x7f2908ec0978>
>>> iter(range(10))
<range_iterator object at 0x7f2908f21db0>
>>> iter(_)
<range_iterator object at 0x7f2908f21db0>
>>> iter(globals())
<dict_keyiterator object at 0x7f2908eb8f98>
>>> iter(_)
<dict_keyiterator object at 0x7f2908eb8f98>

The list, range, and dict (as returned by globals()) are all iterable;
the ...iterator objects are iterators.

I suspect that your use-case is actually looking for iterables, not
iterators, so the fix is simply a docs change. At that point, your
function becomes 100% correct, and a perfectly idiomatic way to
express "iterable that isn't one of these types". It doesn't need to
be a builtin, though.

Incidentally, if you're doing a lot of isinstance tests like this, you
might want to look at the collections module, which has some 'base
classes' which can be used like that.

>>> isinstance([1,2,3],collections.Iterable)
True

ChrisA



More information about the Python-list mailing list