generator-expression生成器表达式

the differences between list comprehension and generator expression

def gen_AB():
    print("start")
    yield 'A'
    print("continue")
    yield 'B'
    print("end.")

res1 = [x*3 for x in gen_AB()]

执行结果为:
start
continue
end.

说明列表推导式会析取yield返回的结果,并存储于列表中,其他的便不会存储到列表中。

for i in res1:
    print("-->",i)

执行结果为:
–> AAA
–> BBB

但是,生成器表达式却不是这样的。

res2 = (x*3 for x in gen_AB())

这时,输入res2,会返回:

<generator object <genexpr> at 0x10063c20>  
for i in res2:
    print("-->", i)

执行结果为:
start
–> AAA
continue
–> BBB
end.

**only when the for loop iterates over res2, the body of gen_AB actually executes.
Each iteration of the for loop implicitly calls the next(res2), advancing gen_AB to the next yield.
Note the output of gen_AB with the output of the print in the for loop**

import re
import reprlib

RE_WORD = re.compile("\w+")

class Sentence(object):
    def __init__(self, text):
        self.text = text

    def __repr__(self):
        return "Sentence({})".format(reprlib.repr(self.text))

    def __iter__(self):
        return (match.group() for match in RE_WORD.finditer(self.text))

when to use generator expression?

if the generator expression spans more than a couple of lines, I prefer to code a generator function for the sake of readability.

Also, because generator function have a name, they can be reused.

You can always name a generator expression and use it later by assigning it to a variable, of course, but that is stretching its intended usage as a one-off generator.

Syntax Tip

when a generator expression is passed as the single argument to a function or constructor, you don’t need to
write a set of parentheses for the function call and another to enclose the generator expression.

def __mul__(self, scalar):

    if isinstance(scalar, numbers.Real):
        return Vector(n*scalar for n in self)# the parentheses is omitted
    else:
        return NotImplemented

look at the generator expression power!

def gen_Arithmetic(start, step, end=None):
    start = type(start+step)(start)
    index = 0
    result = start
    foever = end is None
    while foever or result < end:
        yield result
        index += 1
        result = start + index*step

there is a standard library that can be used.

import itertools
gen = itertools.count(1, 0.5)
next(gen) 

1

next(gen) 

1.5

however, itertools.count never stops.
tertools.takewhile function : it produces a generator that consumer another generator and stop when a given
predicate evaluates to False.

gen = itertools.takewhile(lambda n:n<3, itertools.count(1,0.5))
list(gen) 

[1,1.5,2.0,2.5]

def gen_Arithmetic(start, step, end=None):
    start = type(start + step)(start)
    gen = itertools.count(start,step)
    if end is None:
        return gen
    return itertools.takewhile(lambda v:v<end, gen)

Note that gen_Arithmetic function is not a generator function;
it has no yield in its body.
But it returns a generator, so it operates as a generator factory, just as a generator function does.