2008-12-13 11 views

Odpowiedz

94

Czy rozumiesz rozumienie list? Jeśli tak, wyrażenie generatora jest podobne do rozumienia listy, ale zamiast znajdować wszystkie interesujące Cię elementy i umieszczać je na liście, czeka i usuwa każdy z elementów wyrażenia, jeden po drugim.

>>> my_list = [1, 3, 5, 9, 2, 6] 
>>> filtered_list = [item for item in my_list if item > 3] 
>>> print filtered_list 
[5, 9, 6] 
>>> len(filtered_list) 
3 
>>> # compare to generator expression 
... 
>>> filtered_gen = (item for item in my_list if item > 3) 
>>> print filtered_gen # notice it's a generator object 
<generator object at 0xb7d5e02c> 
>>> len(filtered_gen) # So technically, it has no length 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
TypeError: object of type 'generator' has no len() 
>>> # We extract each item out individually. We'll do it manually first. 
... 
>>> filtered_gen.next() 
5 
>>> filtered_gen.next() 
9 
>>> filtered_gen.next() 
6 
>>> filtered_gen.next() # Should be all out of items and give an error 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
StopIteration 
>>> # Yup, the generator is spent. No values for you! 
... 
>>> # Let's prove it gives the same results as our list comprehension 
... 
>>> filtered_gen = (item for item in my_list if item > 3) 
>>> gen_to_list = list(filtered_gen) 
>>> print gen_to_list 
[5, 9, 6] 
>>> filtered_list == gen_to_list 
True 
>>> 

Ponieważ wyrażenie generatora musi dawać tylko jeden przedmiot na raz, może to prowadzić do dużych oszczędności w wykorzystaniu pamięci. Wyrażenia generatora mają największy sens w scenariuszach, w których trzeba zająć jeden przedmiot na raz, wykonać wiele obliczeń na podstawie tego elementu, a następnie przejść do następnego elementu. Jeśli potrzebujesz więcej niż jednej wartości, możesz również użyć wyrażenia generatora i pobrać kilka naraz. Jeśli potrzebujesz wszystkich wartości, zanim Twój program będzie kontynuował, użyj zamiast tego listy zrozumiałej.

12

Zrozumienie generatora jest leniwą wersją rozumienia listy.

Jest to podobne do rozumienia listy, z tym, że zwraca iterator zamiast listy, czyli obiekt z metodą next(), która da następny element.

Jeśli nie jesteś zaznajomiony ze zrozumieniem listy, zobacz here, a dla generatorów zobacz here.

4

Zrozumienie listy/generatora jest konstrukcją, której można użyć do utworzenia nowej listy/generatora z istniejącej.

Powiedzmy chcesz wygenerować listę kwadratów każdej liczby od 1 do 10. Można to zrobić w Pythonie:

>>> [x**2 for x in range(1,11)] 
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100] 

tutaj, range(1,11) generuje listę [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], ale funkcja range nie jest generator przed Pythonem 3.0, a więc konstrukt, którego użyłem, to zrozumienie listy.

Gdybym chciał stworzyć generator, który robi to samo, co mogłem zrobić to tak:

>>> (x**2 for x in xrange(1,11)) 
<generator object at 0x7f0a79273488> 

W Pythonie 3, jednak range jest generator, więc wynik zależy tylko od składni używasz (nawiasy kwadratowe lub nawiasy okrągłe).

+1

To jest złe. To, czy zewnętrzne wyrażenie jest generatorem, nie ma nic wspólnego z tym, czy wewnętrzna ekspresja jest. Chociaż oczywiście nie ma sensu w wyrażeniu generatora, biorąc elementy z listy, możesz to zrobić. – Antimony

+0

Czy można to napisać jaśniej? Dostaję to, co mówisz, ale jak mówi Antymon, wygląda na to, że mówisz coś innego. (i wygląda na to, że coś jest nie tak) –

2

Zrozumienie generatora to łatwy sposób tworzenia generatorów o określonej strukturze. Powiedzmy, że chcesz generator, który wyprowadza jeden po drugim wszystkie liczby parzyste w your_list. Jeśli go utworzyć za pomocą styl funkcji byłoby tak:

def allEvens(L): 
    for number in L: 
     if number % 2 is 0: 
      yield number 

evens = allEvens(yourList) 

Można osiągnąć ten sam wynik z tego generator rozumienia wyrażenia:

evens = (number for number in your_list if number % 2 == 0) 

w obu przypadkach, gdy dzwonisz next(evens) cię uzyskać kolejny numer parzysty w your_list.

0

Zrozumienie generatora to podejście do tworzenia iterables, coś w rodzaju kursora, który porusza się po zasobach. Jeśli znasz kursor mysql lub kursor mongodb, możesz być świadomy, że wszystkie rzeczywiste dane nigdy nie zostaną załadowane do pamięci naraz, ale pojedynczo. Kursor przesuwa się w tę iz powrotem, ale w pamięci zawsze znajduje się element z jednym wierszem/listą.

Krótko mówiąc, korzystając ze sprawdzania generatorów, można łatwo tworzyć kursory w pythonie.

0

Innym przykładem Generator zrozumieniem:

print 'Generator comprehensions' 

def sq_num(n): 
    for num in (x**2 for x in range(n)):  
     yield num 

for x in sq_num(10): 
    print x 
Powiązane problemy