Skip to main content
Updated the location of the abstract base classes to make them Python >=3.3 compliant.
Source Link

Prior to Python version 3.3 the classes from collections.abc were located directly under collections, e.g. collections.Iterator instead of collections.abc.Iterator.

>>> import collections, types >>> issubclass(types.GeneratorType, collections.abc.Iterator) True 
>>> isinstance(a_generator, collections.abc.Iterator) True 
>>> issubclass(collections.abc.Iterator, collections.abc.Iterable) True 
>>> collections.abc.Iterable() Traceback (most recent call last): File "<pyshell#79>", line 1, in <module> collections.abc.Iterable() TypeError: Can't instantiate abstract class Iterable with abstract methods __iter__ 
>>> all(isinstance(element, collections.abc.Iterable) for element in ( (), [], {}, set(), frozenset(), '', b'', bytearray(), range(0), memoryview(b''))) True 
>>> collections.abc.Iterator() Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: Can't instantiate abstract class Iterator with abstract methods __next__ 
>>> all(isinstance(iter(element), collections.abc.Iterator) for element in ( (), [], {}, set(), frozenset(), '', b'', bytearray(), range(0), memoryview(b''))) True 
>>> import collections, types >>> issubclass(types.GeneratorType, collections.Iterator) True 
>>> isinstance(a_generator, collections.Iterator) True 
>>> issubclass(collections.Iterator, collections.Iterable) True 
>>> collections.Iterable() Traceback (most recent call last): File "<pyshell#79>", line 1, in <module> collections.Iterable() TypeError: Can't instantiate abstract class Iterable with abstract methods __iter__ 
>>> all(isinstance(element, collections.Iterable) for element in ( (), [], {}, set(), frozenset(), '', b'', bytearray(), range(0), memoryview(b''))) True 
>>> collections.Iterator() Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: Can't instantiate abstract class Iterator with abstract methods __next__ 
>>> all(isinstance(iter(element), collections.Iterator) for element in ( (), [], {}, set(), frozenset(), '', b'', bytearray(), range(0), memoryview(b''))) True 

Prior to Python version 3.3 the classes from collections.abc were located directly under collections, e.g. collections.Iterator instead of collections.abc.Iterator.

>>> import collections, types >>> issubclass(types.GeneratorType, collections.abc.Iterator) True 
>>> isinstance(a_generator, collections.abc.Iterator) True 
>>> issubclass(collections.abc.Iterator, collections.abc.Iterable) True 
>>> collections.abc.Iterable() Traceback (most recent call last): File "<pyshell#79>", line 1, in <module> collections.abc.Iterable() TypeError: Can't instantiate abstract class Iterable with abstract methods __iter__ 
>>> all(isinstance(element, collections.abc.Iterable) for element in ( (), [], {}, set(), frozenset(), '', b'', bytearray(), range(0), memoryview(b''))) True 
>>> collections.abc.Iterator() Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: Can't instantiate abstract class Iterator with abstract methods __next__ 
>>> all(isinstance(iter(element), collections.abc.Iterator) for element in ( (), [], {}, set(), frozenset(), '', b'', bytearray(), range(0), memoryview(b''))) True 
>>> def a_function(): "just a function definition with yield in it" yield >>> type(a_function) <class 'function'> >>> a_generator = a_function()  # when called >>> type(a_generator)  # returns a generator <class 'generator'> 

Some examples of iterables are the built-in tuples, lists, dictionaries, sets, dictsfrozen sets, strings, byte strings, byte arrays, ranges and range objectsmemoryviews:

>>> all(isinstance(element, collections.Iterable) for element in (   (), [], {}, set(), frozenset(), '', b'', bytearray(), range(0), memoryview(b''))) True 

We can get the iterators from the builtinbuilt-in objects (or custom objects) with the iter function:

>>> all(isinstance(iter(element), collections.Iterator) for element in (   (), [], {}, set(), frozenset(), '', b'', bytearray(), range(0), memoryview(b''))) True 

The __iter__ function is whatmethod is invokedcalled when you attempt to use an object with a for-loop. Then the __next__ or next method is called on the iterator object to get each item out for the loop. The iterator raises StopIteration when you have exhausted it, and it cannot be reused at that point.

From the docs:documentation

class Yes(collections.Iterator):   def __init__(self, stop): self.x = 0 self.stop = stop   def __iter__(self): return self   def next(self): if self.x < self.stop: self.x += 1 return 'yes' else: # Iterators must raise when done, else considered broken raise StopIteration    __next__ = next # Python 3 compatibility 
>>> stop = 4   >>> for i, ys in enumerate(zip(Yes(stop), yes(stop), ('yes' for _ in range(stop))): >>> for i, y1, y2, y3 in zip(range(stop), Yes(stop), yes(stop), ('yes' for _ in range(stop))): ... print('{0}: {1} == {2} == {3}'.format(i, y1, y2, y3)) ... 0: yes == yes == yes 1: yes == yes == yes 2: yes == yes == yes 3: yes == yes == yes 
>>> def a_function(): "just a function definition with yield in it" yield >>> type(a_function) <class 'function'> >>> a_generator = a_function()  # when called >>> type(a_generator)  # returns a generator <class 'generator'> 

Some examples of iterables are tuples, lists, sets, dicts, strings, and range objects:

>>> all(isinstance(element, collections.Iterable) for element in (   (), [], {}, set(), '', range(0))) True 

We can get the iterators from the builtin objects (or custom objects) with the iter function:

>>> all(isinstance(iter(element), collections.Iterator) for element in (   (), [], {}, set(), '', range(0))) True 

The __iter__ function is what is invoked when you attempt to use an object with a for-loop. Then __next__ or next is called on the iterator object to get each item out for the loop. The iterator raises StopIteration when you have exhausted it, and it cannot be reused at that point.

From the docs:

class Yes(collections.Iterator): def __init__(self, stop): self.x = 0 self.stop = stop def __iter__(self): return self def next(self): if self.x < self.stop: self.x += 1 return 'yes' else: # Iterators must raise when done, else considered broken raise StopIteration  __next__ = next # Python 3 compatibility 
>>> stop = 4   >>> for i, ys in enumerate(zip(Yes(stop), yes(stop), ('yes' for _ in range(stop))): >>> for i, y1, y2, y3 in zip(range(stop), Yes(stop), yes(stop), ('yes' for _ in range(stop))): ... print('{0}: {1} == {2} == {3}'.format(i, y1, y2, y3)) ... 0: yes == yes == yes 1: yes == yes == yes 2: yes == yes == yes 3: yes == yes == yes 
>>> def a_function(): "just a function definition with yield in it" yield >>> type(a_function) <class 'function'> >>> a_generator = a_function() # when called >>> type(a_generator) # returns a generator <class 'generator'> 

Some examples of iterables are the built-in tuples, lists, dictionaries, sets, frozen sets, strings, byte strings, byte arrays, ranges and memoryviews:

>>> all(isinstance(element, collections.Iterable) for element in ( (), [], {}, set(), frozenset(), '', b'', bytearray(), range(0), memoryview(b''))) True 

We can get the iterators from the built-in objects (or custom objects) with the iter function:

>>> all(isinstance(iter(element), collections.Iterator) for element in ( (), [], {}, set(), frozenset(), '', b'', bytearray(), range(0), memoryview(b''))) True 

The __iter__ method is called when you attempt to use an object with a for-loop. Then the __next__ method is called on the iterator object to get each item out for the loop. The iterator raises StopIteration when you have exhausted it, and it cannot be reused at that point.

From the documentation

class Yes(collections.Iterator):   def __init__(self, stop): self.x = 0 self.stop = stop   def __iter__(self): return self   def next(self): if self.x < self.stop: self.x += 1 return 'yes' else: # Iterators must raise when done, else considered broken raise StopIteration   __next__ = next # Python 3 compatibility 
>>> stop = 4 >>> for i, y1, y2, y3 in zip(range(stop), Yes(stop), yes(stop), ('yes' for _ in range(stop))): ... print('{0}: {1} == {2} == {3}'.format(i, y1, y2, y3)) ... 0: yes == yes == yes 1: yes == yes == yes 2: yes == yes == yes 3: yes == yes == yes 
Ambiguity lifted (Generator is often used to mean Generator Function)
Source Link
Eric O. Lebigot
  • 95.1k
  • 49
  • 223
  • 263

However, in the vast majority of cases, you are best suited to use yield to define a function that returns a Generator Iterator or consider Generator Expressions.

However, in the vast majority of cases, you are best suited to use yield to define a function that returns a Generator or consider Generator Expressions.

However, in the vast majority of cases, you are best suited to use yield to define a function that returns a Generator Iterator or consider Generator Expressions.

added 1423 characters in body
Source Link
Aaron Hall
  • 400.1k
  • 93
  • 416
  • 342
Loading
added 2 characters in body
Source Link
Aaron Hall
  • 400.1k
  • 93
  • 416
  • 342
Loading
added 2282 characters in body
Source Link
Aaron Hall
  • 400.1k
  • 93
  • 416
  • 342
Loading
improved a bit.
Source Link
Aaron Hall
  • 400.1k
  • 93
  • 416
  • 342
Loading
Source Link
Aaron Hall
  • 400.1k
  • 93
  • 416
  • 342
Loading