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.
As the ABC documentation mentions:
Checking
isinstance(obj, Iterable)detects classes that are registered asIterableor that have an__iter__()method, but it does not detect classes that iterate with the__getitem__()method. The only reliable way to determine whether an object is iterable is to calliter(obj).
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)) However, this doesn't work because:
your class doesn't implement
__len__(and doesn't need to anyway, being iterable only requires a sequence-compatible__getitem__); andSequenceis a complex interface:Complex interfaces do not support [virtual subclassing] because an interface is more than just the presence of method names. Interfaces specify semantics and relationships between methods that cannot be inferred solely from the presence of specific method names.
so even a class that implements both
__getitem__and__len__doesn't automatically become aSequence, it needs to explicitly extend the ABC (at which point it would inherit an__iter__implementation and becomeIterableanyway).