Co robi generator rozumienia? Jak to działa? Nie mogłem znaleźć samouczka na ten temat.
Co robi generator rozumienia? Jak to działa? Nie mogłem znaleźć samouczka na ten temat.
Odpowiedzi:
Czy rozumiesz listy ze zrozumieniem? Jeśli tak, to wyrażenie generatora jest podobne do wyrażenia listowego, ale zamiast znaleźć wszystkie interesujące Cię elementy i spakować je na listę, czeka i zwraca każdy element z 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 <genexpr> at 0x7f2ad75f89e0>
>>> 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.
...
>>> next(filtered_gen)
5
>>> next(filtered_gen)
9
>>> next(filtered_gen)
6
>>> next(filtered_gen) # 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 element naraz, może to prowadzić do dużych oszczędności w zużyciu pamięci. Wyrażenia generatora są najbardziej sensowne w scenariuszach, w których musisz wziąć jeden element 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 na raz. Jeśli potrzebujesz wszystkich wartości przed kontynuowaniem programu, użyj zamiast tego funkcji list.
next(...)
zamiast .__next__()
w Pythonie 3.
If you need more than one value, you can also use a generator expression and grab a few at a time
. Czy mógłbyś podać przykład tego zastosowania? Dzięki.
Rozumienie przez generator jest leniwą wersją rozumienia listy.
Jest to podobne do wyrażenia listowego, z tym wyjątkiem, że zwraca iterator zamiast listy, tj. Obiekt z metodą next (), która zwróci następny element.
Jeśli nie jesteś zaznajomiony ze składaniem list, zajrzyj tutaj, a informacje o generatorach - tutaj .
Rozumienie listy / generatora jest konstrukcją, której można użyć do utworzenia nowej listy / generatora na podstawie istniejącej.
Powiedzmy, że chcesz wygenerować listę kwadratów każdej liczby od 1 do 10. Możesz 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 range
funkcja nie jest generatorem przed Pythonem 3.0, dlatego konstrukcja, której użyłem, jest złożeniem listowym.
Gdybym chciał stworzyć generator, który robi to samo, mógłbym to zrobić tak:
>>> (x**2 for x in xrange(1,11))
<generator object at 0x7f0a79273488>
Jednak w Pythonie 3 range
jest to generator, więc wynik zależy tylko od używanej składni (nawiasy kwadratowe lub nawiasy okrągłe).
Rozumienie przez generator to łatwy sposób na tworzenie generatorów o określonej strukturze. Powiedzmy, że chcesz, generator
aby wypisywano po kolei wszystkie liczby parzyste your_list
. Jeśli utworzysz go za pomocą stylu funkcji, wyglądałoby to tak:
def allEvens( L ):
for number in L:
if number % 2 is 0:
yield number
evens = allEvens( yourList )
Możesz osiągnąć ten sam wynik za pomocą tego wyrażenia rozumienia generatora:
evens = ( number for number in your_list if number % 2 == 0 )
W obu przypadkach dzwoniąc next(evens)
otrzymasz następny parzysty numer your_list
.
Zrozumienie generatora to podejście do tworzenia elementów iteracyjnych, coś w rodzaju kursora poruszającego się po zasobie. Jeśli znasz kursor mysql lub kursor mongodb, możesz być świadomy, że całe rzeczywiste dane nigdy nie są ładowane do pamięci naraz, ale pojedynczo. Kursor porusza się tam iz powrotem, ale w pamięci zawsze znajduje się jeden wiersz / element listy.
Krótko mówiąc, korzystając ze zrozumienia generatorów, możesz łatwo tworzyć kursory w Pythonie.
Inny przykład zrozumienia przez Generator:
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
Generatory są takie same jak tylko listy, niewielka różnica polega na tym, że na listach wszystkie wymagane liczby lub pozycje z listy uzyskujemy po jedynkach, ale w generatorach wymagane liczby są podawane pojedynczo. Aby uzyskać wymagane przedmioty, musimy użyć pętli for, aby uzyskać wszystkie wymagane przedmioty.
#to get all the even numbers in given range
def allevens(n):
for x in range(2,n):
if x%2==0:
yield x
for x in allevens(10)
print(x)
#output
2
4
6
8