{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"___\n",
"\n",
"\n",
"___\n",
"
def
and the return
statement. Generator functions allow us to write a function that can send back a value and then later resume to pick up where it left off. This type of function is a generator in Python, allowing us to generate a sequence of values over time. The main difference in syntax will be the use of a yield
statement.\n",
"\n",
"In most aspects, a generator function will appear very similar to a normal function. The main difference is when a generator function is compiled they become an object that supports an iteration protocol. That means when they are called in your code they don't actually return a value and then exit. Instead, generator functions will automatically suspend and resume their execution and state around the last point of value generation. The main advantage here is that instead of having to compute an entire series of values up front, the generator computes one value and then suspends its activity awaiting the next instruction. This feature is known as *state suspension*.\n",
"\n",
"\n",
"To start getting a better understanding of generators, let's go ahead and see how we can create some."
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"# Generator function for the cube of numbers (power of 3)\n",
"def gencubes(n):\n",
" for num in range(n):\n",
" yield num**3"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"0\n",
"1\n",
"8\n",
"27\n",
"64\n",
"125\n",
"216\n",
"343\n",
"512\n",
"729\n"
]
}
],
"source": [
"for x in gencubes(10):\n",
" print(x)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Great! Now since we have a generator function we don't have to keep track of every single cube we created.\n",
"\n",
"Generators are best for calculating large sets of results (particularly in calculations that involve loops themselves) in cases where we don’t want to allocate the memory for all of the results at the same time. \n",
"\n",
"Let's create another example generator which calculates [fibonacci](https://en.wikipedia.org/wiki/Fibonacci_number) numbers:"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"def genfibon(n):\n",
" \"\"\"\n",
" Generate a fibonnaci sequence up to n\n",
" \"\"\"\n",
" a = 1\n",
" b = 1\n",
" for i in range(n):\n",
" yield a\n",
" a,b = b,a+b"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"1\n",
"1\n",
"2\n",
"3\n",
"5\n",
"8\n",
"13\n",
"21\n",
"34\n",
"55\n"
]
}
],
"source": [
"for num in genfibon(10):\n",
" print(num)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"What if this was a normal function, what would it look like?"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"def fibon(n):\n",
" a = 1\n",
" b = 1\n",
" output = []\n",
" \n",
" for i in range(n):\n",
" output.append(a)\n",
" a,b = b,a+b\n",
" \n",
" return output"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"[1, 1, 2, 3, 5, 8, 13, 21, 34, 55]"
]
},
"execution_count": 6,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"fibon(10)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Notice that if we call some huge value of n (like 100000) the second function will have to keep track of every single result, when in our case we actually only care about the previous result to generate the next one!\n",
"\n",
"## next() and iter() built-in functions\n",
"A key to fully understanding generators is the next() function and the iter() function.\n",
"\n",
"The next() function allows us to access the next element in a sequence. Lets check it out:"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"def simple_gen():\n",
" for x in range(3):\n",
" yield x"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"# Assign simple_gen \n",
"g = simple_gen()"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"0\n"
]
}
],
"source": [
"print(next(g))"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"1\n"
]
}
],
"source": [
"print(next(g))"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"2\n"
]
}
],
"source": [
"print(next(g))"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {},
"outputs": [
{
"ename": "StopIteration",
"evalue": "",
"output_type": "error",
"traceback": [
"\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
"\u001b[1;31mStopIteration\u001b[0m Traceback (most recent call last)",
"\u001b[1;32m