Checking Whether Something Is Iterable

In Python, how do I determine if an object is iterable?

  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.


  1. 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'

  1. 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__.

Checking whether something is iterable

The proper way to check for iterability is as follows:

function isIterable(obj) {
// checks for null and undefined
if (obj == null) {
return false;
}
return typeof obj[Symbol.iterator] === 'function';
}

Why this works (iterable protocol in depth): https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Iteration_protocols

Since we are talking about for..of, I assume, we are in ES6 mindset.

Also, don't be surprised that this function returns true if obj is a string, as strings iterate over their characters.

How can I check whether an object is iterable statically?

There is an Iterable type that would do just that:

function fn(ary: Iterable<any>) {
for (let value of ary)
console.log(value)
}

Corresponding TypeScript playground here.

Note that Iterable requires on type argument. any allows you to specifically detect just if an object is iterable, although you could go further and specify on what you would like to iterate (eg. Iterable<Number>).

Checking if a class is iterable

Checking if an object is iterable is correctly, as you've done, performed with:

isinstance(obj, collections.Iterable)

The problem here is you're supplying a class to isinstance and not an instance. It is False because isinstance will go ahead and check if type(fib) has an __iter__ method defined:

type(fib).__iter__  # AttributeError

This of course, isn't the case. type(fib) is type which doesn't define an __iter__ method.

If you supply an instance to it, it correctly prints True:

isinstance(fib(), Iterable)  # True

because looking in type(fib()) it will find fib.__iter__.

Alternatively, feeding fib to issubclass performs a similar check that, instead, takes a class as a first argument:

issubclass(fib, Iterable)    # True

Two extra minor things to point out:

  • Using object as an explicit base class is unnecessary in Python 3 (though, if you're developing code that runs on both Py2 and Py3, it is a good thing. (See Python class inherits object for more on this.)
  • According to PEP 8, class names should follow the CapWords convention, so fib should ideally be named Fib.

how to tell a variable is iterable but not a string

Use isinstance (I don't see why it's bad practice)

import types
if not isinstance(arg, types.StringTypes):

Note the use of StringTypes. It ensures that we don't forget about some obscure type of string.

On the upside, this also works for derived string classes.

class MyString(str):
pass

isinstance(MyString(" "), types.StringTypes) # true

Also, you might want to have a look at this previous question.

Cheers.


NB: behavior changed in Python 3 as StringTypes and basestring are no longer defined. Depending on your needs, you can replace them in isinstance by str, or a subset tuple of (str, bytes, unicode), e.g. for Cython users.
As @Theron Luhn mentionned, you can also use six.

Check if object is iterable

You need to assign the result of match to a variable, so you can test if the match succeeded before trying to use the capture groups.

const match = "string".match(/([^/]+)\/(.*)/);
if (match) {
const [, segment1, segment2] = match;
console.log(segment1, segment2);
}

How can I check if an object is an iterator in Python?

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

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.

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.

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)

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.

Check if object is in an iterable using is identity instead of == equality

Use the any function:

if any(x is object for x in lst):
# ...


Related Topics



Leave a reply



Submit