Alex Rivera | Logout

Python: how to determine if an object is iterable?

Asked 2009-12-23T12:13:55.790
1470

Is there a method like isiterable? The only solution I have found so far is to call:

hasattr(myObj, '__iter__')

but I am not sure how foolproof this is.

Edit
Report

3 Answers

1086
  1. Checking for __iter__ works on sequence types, but it would fail on e.g. strings in Python 2. I would like to know the right answer too, until then, here is one possibility (which would work on strings, too):

    try:
        some_object_iterator = iter(some_object)
    except TypeError as te:
        print(some_object, 'is not iterable')
    

    The iter built-in checks for the __iter__ method or in the case of strings the __getitem__ method.

  2. Another general pythonic approach is to assume an iterable, then fail gracefully if it does not work on the given object. The Python glossary:

    Pythonic programming style that determines an object's type by inspection of its method or attribute signature rather than by explicit relationship to some type object ("If it looks like a duck and quacks like a duck, it must be a duck.") By emphasizing interfaces rather than specific types, well-designed code improves its flexibility by allowing polymorphic substitution. Duck-typing avoids tests using type() or isinstance(). Instead, it typically employs the EAFP (Easier to Ask Forgiveness than Permission) style of programming.

    ...

    try:
       _ = (e for e in my_object)
    except TypeError:
       print(my_object, 'is not iterable')
    
  3. The collections module provides some abstract base classes, which allow to ask classes or instances if they provide particular functionality, for example:

    from collections.abc import Iterable
    
    if isinstance(e, Iterable):
        # e is iterable
    

    However, this does not check for classes that are iterable through __getitem__.

answered 2009-12-23T12:16:43.617
24

In Python <= 2.5, you can't and shouldn't - iterable was an "informal" interface.

But since Python 2.6 and 3.0 you can leverage the new ABC (abstract base class) infrastructure along with some builtin ABCs which are available in the collections module:

from collections import Iterable

class MyObject(object):
    pass

mo = MyObject()
print isinstance(mo, Iterable)
Iterable.register(MyObject)
print isinstance(mo, Iterable)

print isinstance("abc", Iterable)

Now, whether this is desirable or actually works, is just a matter of conventions. As you can see, you can register a non-iterable object as Iterable - and it will raise an exception at runtime. Hence, isinstance acquires a "new" meaning - it just checks for "declared" type compatibility, which is a good way to go in Python.

On the other hand, if your object does not satisfy the interface you need, what are you going to do? Take the following example:

from collections import Iterable
from traceback import print_exc

def check_and_raise(x):
    if not isinstance(x, Iterable):
        raise TypeError, "%s is not iterable" % x
    else:
        for i in x:
            print i

def just_iter(x):
    for i in x:
        print i


class NotIterable(object):
    pass

if __name__ == "__main__":
    try:
        check_and_raise(5)
    except:
        print_exc()
        print

    try:
        just_iter(5)
    except:
        print_exc()
        print

    try:
        Iterable.register(NotIterable)
        ni = NotIterable()
        check_and_raise(ni)
    except:
        print_exc()
        print

If the object doesn't satisfy what you expect, you just throw a TypeError, but if the proper ABC has been registered, your check is unuseful. On the contrary, if the __iter__ method is available Python will automatically recognize object of that class as being Iterable.

So, if you just expect an iterable, ite

answered 2009-12-23T13:35:47.977
19

You could try this:

def iterable(a):
    try:
        (x for x in a)
        return True
    except TypeError:
        return False

If we can make a generator that iterates over it (but never use the generator so it doesn't take up space), it's iterable. Seems like a "duh" kind of thing. Why do you need to determine if a variable is iterable in the first place?

answered 2009-12-23T12:21:12.017

Your Answer