What exactly does "iterable" mean in Python? Why isn't my object which implements `__getitem__()` an iterable?
I think the point of confusion here is that, although implementing __getitem__
does allow you to iterate over an object, it isn't part of the interface defined by Iterable
.
The abstract base classes allow a form of virtual subclassing, where classes that implement the specified methods (in the case of Iterable
, only __iter__
) are considered by isinstance
and issubclass
to be subclasses of the ABCs even if they don't explicitly inherit from them. It doesn't check whether the method implementation actually works, though, just whether or not it's provided.
For more information, see PEP-3119, which introduced ABCs.
using
isinstance(e, collections.Iterable)
is the most pythonic way to check if an object is iterable
I disagree; I would use duck-typing and just attempt to iterate over the object. If the object isn't iterable a TypeError
will be raised, which you can catch in your function if you want to deal with non-iterable inputs, or allow to percolate up to the caller if not. This completely side-steps how the object has decided to implement iteration, and just finds out whether or not it does at the most appropriate time.
To add a little more, I think the docs you've quoted are slightly misleading. To quote the iter
docs, which perhaps clear this up:
object must be a collection object which supports the iteration protocol (the
__iter__()
method), or it must support the sequence protocol (the__getitem__()
method with integer arguments starting at0
).
This makes it clear that, although both protocols make the object iterable, only one is the actual "iteration protocol", and it is this that isinstance(thing, Iterable)
tests for. Therefore we could conclude that one way to check for "things you can iterate over" in the most general case would be:
isinstance(thing, (Iterable, Sequence))
although this does also require you to implement __len__
along with __getitem__
to "virtually sub-class" Sequence
.