## Introduction to generators in Python 3.4

Posted by Ed on April 22, 2015

In this blog post I will explain how generators are used in Python 3.4.

**1. Printing square numbers by creating a list**

Suppose we wanted to print the first ten square numbers. Here is how we can do it in Python 3.4:

def squares_list(n): return [ i*i for i in range(1, n+1) ] squares = squares_list(10) for num in squares: print(num)

The output is:

1 4 9 16 25 36 49 64 81 100

Obviously we created a list and therefore used up some memory. Is it possible to do the same without creating a list and allocating that extra memory, and by same I mean we retain this part of the code:

for num in squares: print(num)

**2. Printing square numbers by creating a generator**

Indeed it is possible with a so-called generator. Let’s rewrite the code from above using a generator:

def squares_gen(n): i = 1 while i <= n: yield i*i i += 1 squares = squares_gen(10) for num in squares: print(num)

We get the same output as previously with the advantage that we did not have allocate memory to create a list.

**3. Understanding the generator**

How does the generator `squares_gen`

work? Let’s have a look at the following code:

def squares_gen(n): i = 1 while i <= n: yield i*i i += 1 squares = squares_gen(10) num = next(squares) print(num) num = next(squares) print(num) num = next(squares) print(num) num = next(squares) print(num)

The output is:

1 4 9 16

When we call `next(squares)`

the first time, the code inside of `squares_gen`

is executed until it encounters the keyword `yield`

. The value 1*1 is then returned to `num`

and the generator `squares_gen`

pauses.

The second time we call `next(squares)`

the generator resumes from where it paused until it encounters the keyword `yield`

again. The same happens when we call `next(squares)`

the third and fourth time.

Let’s add two print statements to our code to emphasize this pausing behaviour:

def squares_gen(n): i = 1 while i <= n: print("right before yield") yield i*i print("resuming after yield") i += 1 squares = squares_gen(10) num = next(squares) print(num, '\n') num = next(squares) print(num, '\n') num = next(squares) print(num, '\n') num = next(squares) print(num, '\n')

The output is:

right before yield 1 resuming after yield right before yield 4 resuming after yield right before yield 9 resuming after yield right before yield 16

Be careful though when you call `next()`

because doing so more than ten times will cause an error due to the line `squares = squares_gen(10)`

. When we use the syntax `for ... in ...`

, we don’t have to worry about this. All the `next()`

calls happen automatically.

**4. Generator instead of list comprehension**

Let’s print the first ten cube numbers:

cube_list = [i**3 for i in range(1, 11)] for num in cube_list: print(num)

Again, we can avoid creating the list by using a generator. In this case we can transform the list comphrehension into a generator by simply replacing the square brackets by parantheses:

cube_gen = (i**3 for i in range(1, 11)) for num in cube_gen: print(num)

The output is:

1 8 27 64 125 216 343 512 729 1000

**References**

1. What can you use Python generator functions for?

2. Behaviour of Python’s “yield”

3. Difference between Python’s Generators and Iterators

4. Generator Expressions vs. List Comprehension

**Exercise**

Print the first ten numbers in the Fibonacci sequence by using a) a list and b) a generator.

**Solution**

**a)** Here is the Python 3.4 code that prints the first ten Fibonacci numbers using a list:

def fibo_list(n): a, b = 0, 1 L = [] for i in range(n): L.append(a) a, b = b, a+b return L fibo_nums = fibo_list(10) for num in fibo_nums: print(num)

**b)** Here is the Python 3.4 code that prints the first ten Fibonacci numbers using a generator:

def fibo_gen(n): a, b = 0, 1 for i in range(n): yield a a, b = b, a+b fibo_nums = fibo_gen(10) for num in fibo_nums: print(num)

In both a) and b) the output is:

0 1 1 2 3 5 8 13 21 34

## Permutations in Python 3.4 | Programming, algorithms and data structures said

[…] One reason why this method is more efficient than the first is that itertools.permutations() is a generator, and as such it does not allocate additional memory for a […]