Python in Detail: Prime Iterator Example
Welcome to the Prime Iterator Example lesson!
This lesson is shown as static text below. However, it's designed to be used interactively. Click the button below to start!
In an earlier lesson, we created our own iterable data types. Their
.__iter__methods returned iterators, which kept track of the iteration progress while we looped over the data.This lesson explores a powerful fact about iterators: they can represent infinite amounts of data, or data streams that never end. For example, the data might be streamed over a network, or generated one element at a time. In this lesson, we'll build an infinite iterable that gives us all prime numbers.
First, we need a way to find individual prime numbers. A number is prime if it's only divisible by itself and 1.
We'll use the modulo operator,
%, to test for divisibility.x % ygives the modulo or "remainder" of dividingxbyy. For example,x % 2tells us whether x is even or odd.x % 2 == 0for even numbers andx % 2 == 1for odd numbers.>
99 % 2Result:
1
>
100 % 2Result:
0
In the next example, we apply
n % 4to many numbers. The result is always between 0 and 3. Note that the modulos are cyclic: the count from 0 to 3, then start over again. Whenever the number is divisible by 4 (like 0, 4, 8, etc.), the modulo is 0.>
numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12][n % 4 for n in numbers]Result:
>
14 % 4Result:
2
If
nis prime, thenn % i !== 0for all integersithat are less thann.(The code shown below has a slightly more complex loop condition than that. It's still correct, but it improves performance.)
>
def is_prime(n):for i in range(2, n // 2 + 1):if n % i == 0:return Falsereturn True- Note: this code example reuses elements (variables, etc.) defined in earlier examples.
>
is_prime(2)Result:
- Note: this code example reuses elements (variables, etc.) defined in earlier examples.
>
is_prime(100)Result:
False
- Note: this code example reuses elements (variables, etc.) defined in earlier examples.
>
is_prime(13)Result:
True
The
Primesiterable is very simple: its.__iter__method returnsPrimesIterator, where the real work happens.- Note: this code example reuses elements (variables, etc.) defined in earlier examples.
>
class Primes:def __iter__(self):return PrimesIterator() PrimesIteratortracks which prime we're currently on. Its.__next__method calls.increment_to_next_prime, which uses theis_primefunction shown above to calculate the next prime number.- Note: this code example reuses elements (variables, etc.) defined in earlier examples.
>
class PrimesIterator:def __init__(self):self.current_prime = 2def __next__(self):current_prime = self.current_primeself.increment_to_next_prime()return current_primedef increment_to_next_prime(self):while True:self.current_prime += 1if is_prime(self.current_prime):return Now we have a working prime iterator! Below, we generate the first five primes: 2, 3, etc.
- Note: this code example reuses elements (variables, etc.) defined in earlier examples.
>
my_iter = iter(Primes())(next(my_iter), next(my_iter), next(my_iter), next(my_iter), next(my_iter))Result:
(2, 3, 5, 7, 11)
Note that we only keep one number in memory:
.current_prime. Each time we call.__next__, we start at that number, and count up until we find the next prime.There are infinitely many prime numbers, so our iterator is infinitely long. But we can consume only a few values from it, and that works perfectly well even on our finite computers.
However, there's a danger here. If we use the iterator in a way that tries to bring all of its items into memory at once, that won't work. Calling
list(Primes())would load primes in an infinite loop, eventually running out of memory. We won't show that here because the infinite loop would lock your browser up. But we can dig deeper into the prime list to see that it really does work.- Note: this code example reuses elements (variables, etc.) defined in earlier examples.
>
my_iter = iter(Primes())for _ in range(200):next(my_iter)next(my_iter)Result:
Generating primes shows us how powerful iterators are. First, they can iterate over data even if we don't have all of the data yet (for example, if it's streaming over a network.) In that case,
next(the_iterator)will have to wait ("block") until more data shows up.Second, as we saw with
PrimesIterator, iterators can be infinite in length. Every computer is finite, so we can never load the full contents of an infinite iterator into memory. But iterators iterate over data only as it's needed, so they can represent infinite sequences of data without ever having to store it all in memory at the same time.In this lesson, our
PrimesIteratorclass was quite long for such a simple task. That's good, because it lets us see the details of how an infinite iterator works. But there's also a much shorter way to write an infinite prime number iterator. In a future lesson on generators, we'll see that shorter version!