In Python, how do I determine if an object is iterable?
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.
- 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'
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__
.
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.
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 Python3
(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 namedFib
.
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):
# ...
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
.
In Python, how do I determine if an iterable has stable iteration order?
One thing you might be looking for is collections.Sequence
. This is a bit more specific than what you want, since according to the docs a sequence "supports efficient element access using integer indices"; it's also not specific enough, since nothing explicitly guarantees that getting the same index twice has to return the same value both times. But this would suffice to distinguish lists and tuples from dicts and sets.
However, in general there is no way. In general there cannot be a way, because you can write any iterable you like and there's no requirement that you specify whether it's stable or not. E.g., you can do something like this:
>>> def f():
... if random.random() < 0.5:
... for a in xrange(10):
... yield a
... else:
... stuff = range(10)
... random.shuffle(stuff)
... for a in stuff:
... yield a
>>> list(f())
0: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> list(f())
1: [7, 0, 2, 8, 5, 1, 4, 3, 6, 9]
The fact that iterators can be written without having to declare whether they are stable or not, together with the fact that there isn't a way to tell by iterating over something whether it will iterate the same way later, means that there can be no way to tell if a given iterator is stable or not.
I would advise you to simply document that your function needs stability of iteration order. You can also explicitly check for builtin types that you know might not be stable, and raise an error on those. But there is no way to check in general for the stability of an arbitrary user-defined iterator's stability.
Related Topics
How to Modify List Entries During For Loop
Tkinter - Executing Functions Over Time
How to Find the Duplicates in a List and Create Another List With Them
Converting Unix Timestamp String to Readable Date
Selecting Multiple Columns in a Pandas Dataframe
What Exactly Is Current Working Directory
Count the Frequency That a Value Occurs in a Dataframe Column
How to Programmatically Set an Attribute
How to Call a Function from Another .Py File
Pip Install Failing With: Oserror: [Errno 13] Permission Denied on Directory
How to Sort a List of Objects Based on an Attribute of the Objects
Installing Python Module Within Code
Return, Return None, and No Return At All
How to Change the Order of Dataframe Columns
Delete a Column from a Pandas Dataframe
How to Count the Frequency of the Elements in an Unordered List