9 lutego 2013

Generator expressions i generator function - Python

Generatory są szczególnie przydatne, gdy nie chcemy znać wszystkich wyników jakie może zwracać funkcja, a jedynie pierwszy, który będzie spełniać nasze kryteria. Generowanie kolejnych wyników, jest triggerowane przez nas.

Generatory expresion budujemy podobnie jak list comprehension (w tym celu korzystamy z nawiasów '()'). Aby wymusić wygenerowanie kolejnego wyniku korzystamy z metody bądź funkcji next(). Gdy generator nie jest w stanie już nic wygenerować, rzucany jest wyjątek "StopIteration".
gen_expression = (val for val in [1, 2, 3, 4, 7] if val % 2)

try:
    print gen_expression.next()
    print next(gen_expression)
    print gen_expression.next()
    print gen_expression.next()
except StopIteration:
    print 'Dostalem wyjatek'
Wynik:
1
3
7
Dostalem wyjatek
Drugim rodzajem generatora jest generator function, który wygląda jak zwykła funkcja. Pozwala jednak na korzystanie mechanizmu yield. W momencie, gdy metoda trafi na takie miejsce, jej działanie jest przerywane i zwracana jest kontrola do naszej części kodu.
def gen_fun(arg = 1):
    num = 0
    yield num
    while True:
        num += arg
        yield num
        yield -num

# Zwraca generator object
g = gen_fun()
print [g.next() for _ in xrange(15)]
Wynik:
[0, 1, -1, 2, -2, 3, -3, 4, -4, 5, -5, 6, -6, 7, -7]
Możemy również przekazać jakąś wartość do wnętrza generatora. W tym celu należy skorzystać z metody send(), które tak jak next() wznawia jego działanie. Jeżeli na takim generatorze zawołamy tylko next(), do środka przekazana zostanie wartość None.
def gen():
    arg = 1
    num = 0
    while True:
        num += arg
        a = yield num
        if a is not None:
            arg = a

g = gen()
print g.next()
print g.next()
print g.send(100)
print g.next()
Wynik:
1
2
102
202

Brak komentarzy:

Prześlij komentarz