Leniwa ocena (lazy evaluation) to kluczowa koncepcja efektywnego programowania, w której wartości są obliczane tylko wtedy, gdy jest to konieczne. Historycznie w Pythonie wszystkie podstawowe wbudowane struktury (listy, krotki) były "wygodne": wcześniej tworzyły i umieszczały w pamięci wszystkie elementy. Wraz ze wzrostem objętości danych i zadań związanych z przetwarzaniem strumieni pojawiła się potrzeba leniwych obliczeń.
Problem: wygodne obliczenia prowadzą do nieefektywnego wykorzystania pamięci i czasu tam, gdzie można stopniowo uzyskiwać wyniki — na przykład przy filtrowaniu, przekształcaniu dużych kolekcji lub strumieniowaniu plików.
Rozwiązanie: w Pythonie powstało wiele narzędzi do leniwych obliczeń: generatory, iteratory oraz funkcje standardowej biblioteki (map, filter, zip, enumerate) i moduł itertools. Wszystkie one zwracają nie gotowe kolekcje, a "leniwe" obiekty, które wydają wynik jeden element na raz.
Przykład kodu:
result = map(lambda x: x * x, range(100)) # zwróci generator-iterator for y in result: print(y) # wartości obliczane są na żądanie import itertools inf = itertools.count(1) for i in inf: if i > 3: break print(i) # 1, 2, 3
Kluczowe cechy:
Czy funkcje map/filter zawsze zwracają listę w Pythonie 3?
Nie, w Pythonie 3 te funkcje zwracają iteratory, a nie listy. Aby uzyskać listę, należy owinąć wynik w list().
x = map(int, ['1', '2']) # <map object> list(x) # [1, 2]
Czy można uzyskać długość wyniku map bez konwersji do listy?
Nie, iterator nie zna z góry, ile ma elementów, dopóki nie przejdzie przez wszystkie. Należy obliczyć przez list(), co unieważnia leniwość.
Funkcja range w Pythonie 3 — jest wygodna czy leniwa?
Leniwa: range tworzy "obiekt range" — oblicza elementy na żądanie, nie przechowując całej sekwencji.
Skrypt przetwarza ogromny plik CSV, tworząc listę wszystkich wierszy przez list(open(f)). Serwer "umiera" z powodu braku pamięci przy dużym pliku.
Zalety:
Wady:
Kod używa leniwej obróbki: przechodzi przez wiersze pliku iteratorem for line in open(f), lub przetwarza je przez map/filter bez tworzenia pośrednich kolekcji.
Zalety:
Wady: