Looking a instance's class hierarchy in Python
Question: Taking `zip` for example. I just want to know is it an `Iterable` or
`Iterator` or `Generator` .

so I put this:

    
    
    zip(x,y).__class__ 
    

it prints: zip  
Why class name are lowercase?

    
    
    import inspect
    inspect.getmro(zip) 
    zip.__base__ 
    

It prints: (zip, object)  
That's impossible. Python doc says `zip` returns an `iterator` (or
`generator`?), but `zip` apparently is not inherited from Iterator or alikes
according what `getmro` prints.

So the two questions ,thanks for help.


Answer: Nothing in Python inherits from `Iterator` or `Iterable`, as they embody a
_protocol_. Python looks for the [`__iter__` and `__next__`
methods](https://docs.python.org/3/library/stdtypes.html#typeiter), not for a
specific base class. Any object can be an iterable or iterator, simply by
implementing those methods.

`zip()` is a built-in function defined in C code, and it follows the naming
convention for all built-ins; these are always in lowercase; the type it
returns is not all that relevant here and follows the function name.

The
[`collections.abc.Iterable`](https://docs.python.org/3/library/collections.abc.html#collections.abc.Iterable)
and
[`collections.abc.Iterator`](https://docs.python.org/3/library/collections.abc.html#collections.abc.Iterable)
classes are _abstract base classes_ ; they implement [special
hooks](https://docs.python.org/3/reference/datamodel.html#customizing-
instance-and-subclass-checks) that essentially return `True` if the instance
or subclass against which you are test implement the required methods.

`zip()` is both an iterable (it has an `__iter__` method) and an iterator
(`__iter__` returns the object itself and it has a `__next__` method):

    
    
    >>> from collections.abc import Iterator, Iterable
    >>> zip_instance = zip('')
    >>> type(zip_instance)
    <class 'zip'>
    >>> isinstance(zip_instance, Iterator)
    True
    >>> isinstance((zip_instance, Iterable)
    True
    >>> zip_instance.__iter__
    <method-wrapper '__iter__' of zip object at 0x10f2d8348>
    >>> zip_instance.__iter__() is zip_instance
    True
    >>> zip_instance.__next__
    <method-wrapper '__next__' of zip object at 0x10f2d8348>
    

`zip()` is not a generator, as it doesn't have any of the [special generator
methods](https://docs.python.org/3/reference/expressions.html#generator-
iterator-methods):

    
    
    >>> hasattr(zip_instance, 'send')
    False
    >>> hasattr(zip_instance, 'throw')
    False
    >>> hasattr(zip_instance, 'close')
    False
    

