Type checking: an iterable type that is not a string

user2555451 picture user2555451 · Nov 13, 2013 · Viewed 9.6k times · Source

To explain better, consider this simple type checker function:

from collections import Iterable
def typecheck(obj):
    return not isinstance(obj, str) and isinstance(obj, Iterable)

If obj is an iterable type other than str, it returns True. However, if obj is a str or a non-iterable type, it returns False.

Is there any way to perform the type check more efficiently? I mean, it seems kinda redundant to check the type of obj once to see if it is not a str and then check it again to see if it is iterable.

I thought about listing every other iterable type besides str like this:

return isinstance(obj, (list, tuple, dict,...))

But the problem is that that approach will miss any other iterable types that are not explicitly listed.

So...is there anything better or is the approach I gave in the function the most efficient?

Answer

Pi Marillion picture Pi Marillion · Nov 13, 2013

In python 2.x, Checking for the __iter__ attribute was helpful (though not always wise), because iterables should have this attribute, but strings did not.

def typecheck(obj): return hasattr(myObj, '__iter__')

The down side was that __iter__ was not a truely Pythonic way to do it: Some objects might implement __getitem__ but not __iter__ for instance.

In Python 3.x, strings got the __iter__ attribute, breaking this method.

The method you listed is the most efficient truely Pythonic way I know in Python 3.x:

def typecheck(obj): return not isinstance(obj, str) and isinstance(obj, Iterable)

There is a much faster (more efficient) way, which is to check __iter__ like in Python 2.x, and then subsequently check str.

def typecheck(obj): return hasattr(obj, '__iter__') and not isinstance(obj, str)

This has the same caveat as in Python 2.x, but is much faster.