What exactly does "iterable" mean in Python?
Question: First I want to clarify, I'm NOT asking what is "iterator".

This is how the term "iterable" is defined in Python's
[doc](https://docs.python.org/3/glossary.html#term-iterable):

> **iterable**  
>  **An object capable of returning its members one at a time.** Examples of
> iterables include all sequence types (such as list, str, and tuple) and some
> non-sequence types like dict, file objects, and objects of any classes you
> define with an **__iter__() or __getitem__()** method. Iterables can be used
> in a for loop and in many other places where a sequence is needed (zip(),
> map(), ...). When an iterable object is passed as an argument to the built-
> in function iter(), it returns an iterator for the object. This iterator is
> good for one pass over the set of values. When using iterables, it is
> usually not necessary to call iter() or deal with iterator objects yourself.
> The for statement does that automatically for you, creating a temporary
> unnamed variable to hold the iterator for the duration of the loop. See also
> iterator, sequence, and generator.

As [other people suggested](http://stackoverflow.com/questions/1952464/in-
python-how-do-i-determine-if-an-object-is-iterable?lq=1), using `isinstance(e,
collections.Iterable)` is the most pythonic way to check if an object is
iterable.  
So I did some test with Python 3.4.3:

    
    
    from collections.abc import Iterable
    
    class MyTrain:
        def __getitem__(self, index):
            if index > 3:
                raise IndexError("that's enough!")
    
            return index
    
    for name in MyTrain():
        print(name)  # 0, 1, 2, 3
    
    print(isinstance(MyTrain(), Iterable))  # False
    

The result is quite strange: `MyTrain` has defined `__getitem__` method, but
it is not considered as an iterable object, not to mention it's capable of
returning one number at a time.

Then I removed `__getitem__` and added the `__iter__` method:

    
    
    from collections.abc import Iterable
    
    class MyTrain:    
        def __iter__(self):
            print("__iter__ called")
            pass
    
    print(isinstance(MyTrain(), Iterable))  # True
    
    for name in MyTrain():
        print(name)  # TypeError: iter() returned non-iterator of type 'NoneType'
    

It is now considered as a "true" iterable object in spite of it cannot produce
anything while iterating.

So did I misunderstand something or is the documentation incorrect?


Answer: 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`](https://docs.python.org/3/library/collections.abc.html#collections.abc.Iterable)_.

The [abstract base classes](https://docs.python.org/3/glossary.html#term-
abstract-base-class) 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](https://www.python.org/dev/peps/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](https://docs.python.org/3/glossary.html#term-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](https://docs.python.org/3/library/functions.html#iter), 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 at `0`).

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`.

