programowanieProgramista Python

Wyjaśnij, czym są generatory w Pythonie. Jak działają, do czego są używane i jakie są różnice w stosunku do wyrażeń listowych?

Zdaj rozmowy kwalifikacyjne z asystentem AI Hintsage

Odpowiedź.

Generatory to specjalne obiekty iterowalne w Pythonie, które pozwalają na tworzenie sekwencji "na bieżąco", nie zajmując pamięci pod całą kolekcję od razu. Są realizowane za pomocą funkcji z użyciem słowa kluczowego yield lub wyrażeń generatorów ((expr for ... in ...)). To jest wygodne podczas pracy z dużymi ilościami danych lub potencjalnie nieskończonymi strumieniami.

Kluczowe różnice w stosunku do wyrażeń listowych:

  • Wyrażenia listowe ([x for x in range(10)]) tworzą od razu całą listę w pamięci.
  • Generatory ((x for x in range(10))) tworzą elementy jeden po drugim, zużywając znacznie mniej pamięci.

Kiedy używać generatorów:

  • Jeśli nie potrzebny jest dostęp do elementów po indeksie.
  • Jeśli dane są zbyt duże, aby przechować je w pamięci.
  • Przy organizowaniu przetwarzania strumieniowego danych (np. czytanie wierszy z pliku).
# Funkcja generatorowa def counter(n): for i in range(n): yield i for number in counter(5): print(number)

Pytanie z haczykiem.

"Jaka jest różnica między używaniem funkcji z yield a zwykłą funkcją, która zwraca listę? Podaj przykład."

Odpowiedź: Zwykła funkcja natychmiast oblicza i zwraca listę, zajmując pamięć pod wszystkie jej elementy. Funkcja z yield zwraca generator, który wydaje elementy jeden po drugim i nie ładuje całej sekwencji do pamięci od razu.

def make_list(n): return [i for i in range(n)] # Zwróci od razu listę, zajmuje dużo pamięci def make_generator(n): for i in range(n): yield i # Będzie wydawać jeden element

Przykłady rzeczywistych błędów wynikających z braku znajomości tematu.


Historia

W projekcie do analizy dużych logów używano wyrażeń listowych do wyodrębnienia wierszy zawierających błędy:

error_lines = [line for line in open('biglog.txt') if 'ERROR' in line]

Plik przekraczał 2 GB, a aplikacja zakończyła działanie z OOM (Out of Memory). Należało użyć generatora:

error_lines = (line for line in open('biglog.txt') if 'ERROR' in line)

Historia

Pracownik chciał przeanalizować krótki wykaz, napisał funkcję z yield, ale zapomniał, że zwracany jest generator, a nie lista:

result = my_generator_function() # result — generator, a nie lista if len(result) > 5: # TypeError: obiekt typu 'generator' nie ma długości

Poprawka: owinąć wynik w list().


Historia

Próbowali iterować po generatorze kilka razy:

numbers = (i for i in range(5)) for n in numbers: pass # wyczerpano generator for n in numbers: print(n) # nic nie wyświetla

Generator jest jednorazowy. Należy stworzyć nowy, aby ponownie go użyć.