$ curl cheat.sh/
#  **Note: this post assumes Python 3.x syntax.**<sup>&dagger;</sup>
#  
#  A [generator][1] is simply a function which returns an object on which
#  you can call `next`, such that for every call it returns some value,
#  until it raises a `StopIteration` exception, signaling that all values
#  have been generated. Such an object is called an *iterator*.
#  
#  Normal functions return a single value using `return`, just like in
#  Java. In Python, however, there is an alternative, called `yield`.
#  Using `yield` anywhere in a function makes it a generator. Observe
#  this code:

 >>> def myGen(n):
 ...     yield n
 ...     yield n + 1
 ... 
 >>> g = myGen(6)
 >>> next(g)
 6
 >>> next(g)
 7
 >>> next(g)
 Traceback (most recent call last):
   File "<stdin>", line 1, in <module>
 StopIteration

#  As you can see, `myGen(n)` is a function which yields `n` and `n + 1`.
#  Every call to [`next`][2] yields a single value, until all values have
#  been yielded. `for` loops call `next` in the background, thus:

 >>> for n in myGen(6):
 ...     print(n)
 ... 
 6
 7

#  Likewise there are [*generator expressions*][3], which provide a means
#  to succinctly describe certain common types of generators:

 >>> g = (n for n in range(3, 5))
 >>> next(g)
 3
 >>> next(g)
 4
 >>> next(g)
 Traceback (most recent call last):
   File "<stdin>", line 1, in <module>
 StopIteration

#  Note that generator expressions are much like [*list
#  comprehensions*][4]:

 >>> lc = [n for n in range(3, 5)]
 >>> lc
 [3, 4]

#  Observe that a generator object is generated *once*, but its code is
#  *not* run all at once. Only calls to `next` actually execute (part of)
#  the code. Execution of the code in a generator stops once a `yield`
#  statement has been reached, upon which it returns a value. The next
#  call to `next` then causes execution to continue in the state in which
#  the generator was left after the last `yield`. This is a fundamental
#  difference with regular functions: those always start execution at the
#  "top" and discard their state upon returning a value.
#  
#  There are more things to be said about this subject. It is e.g.
#  possible to `send` data back into a generator ([reference][5]). But
#  that is something I suggest you do not look into until you understand
#  the basic concept of a generator.
#  
#  Now you may ask: why use generators? There are a couple of good
#  reasons:
#  
#  * Certain concepts can be described much more succinctly using
#  generators.
#  * Instead of creating a function which returns a list of values, one
#  can write a generator which generates the values on the fly. This
#  means that no list needs to be constructed, meaning that the resulting
#  code is more memory efficient. In this way one can even describe data
#  streams which would simply be too large to fit in memory.
#  * Generators allow for a natural way to describe *infinite* streams.
#  Consider for example the [Fibonacci numbers][6]:

     >>> def fib():
     ...     a, b = 0, 1
     ...     while True:
     ...         yield a
     ...         a, b = b, a + b
     ... 
     >>> import itertools
     >>> list(itertools.islice(fib(), 10))
     [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]

 This code uses [`itertools.islice`][7] to take a finite number of elements from an infinite stream. You are advised to have a good look at the functions in the [`itertools`][8] module, as they are essential tools for writing advanced generators with great ease.

#  ---
#  &nbsp;&nbsp;<sup>&dagger;</sup> **About Python <=2.6:** in the above
#  examples `next` is a function which calls the method `__next__` on the
#  given object. In Python <=2.6 one uses a slightly different technique,
#  namely `o.next()` instead of `next(o)`. Python 2.7 has `next()` call
#  `.next` so you need not use the following in 2.7:

 >>> g = (n for n in range(3, 5))
 >>> g.next()
 3

  #  [1]: http://www.python.org/dev/peps/pep-0255/
  #  [2]: http://docs.python.org/3/library/functions.htmlnext
  #  [3]: http://www.python.org/dev/peps/pep-0289/
  #  [4]: http://docs.python.org/3/tutorial/datastructures.htmllist-
#  comprehensions
  #  [5]: http://docs.python.org/3/reference/expressions.htmlyield-
#  expressions
  #  [6]: http://en.wikipedia.org/wiki/Fibonacci_number
  #  [7]:
#  http://docs.python.org/3/library/itertools.htmlitertools.islice
  #  [8]: http://docs.python.org/3/library/itertools.html
#  
#  [Stephan202] [so/q/1756096] [cc by-sa 3.0]

$
Follow @igor_chubin cheat.sh