# Learntofish's Blog

## 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
```

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
```