Functions, Iterators, and Generators
A display includes the enclosing literal syntax: [x**2 for x in range(10)]; this
example is a list comprehension, which creates a list object from the enclosed generator
expression. In this section, we're going to focus on the generator expression. We'll
occasionally create a display as part of demonstrating how the generator works.
Displays have the disadvantage of creating (potentially large) collection objects.
A generator expression is lazy and creates objects only as required.
We have to provide two important caveats on generator expressions, as follows:
- Generators appear to be sequence-like except for a function such as the len()
function that needs to know the size of the collection. - Generators can be used only once. After that, they appear empty.
Here is a generator function that we'll use for some examples:
def pfactorsl(x):
if x % 2 == 0:
yield 2
if x//2 > 1:
yield from pfactorsl(x//2)
return
for i in range(3,int(math.sqrt(x)+.5)+1,2):
if x % i == 0:
yield i
if x//i > 1:
yield from pfactorsl(x//i)
return
yield x
We're locating the prime factors of a number. If the number, x, is even, we'll yield 2
and then recursively yield all factors of x÷2.
For odd numbers, we'll step through odd values greater than or equal to 3, to locate
a candidate factor of the number. When we locate a factor, we'll yield that factor, i,
and then recursively yield all factors of x÷i.
In the event that we can't locate a factor, the number must be prime, so we can
yield that.
We handle 2 as a special case to cut the number of iterations in half. All prime numbers,
except 2, are odd.