Генераторы и итераторы
Генераторные функции
def count_up_to(n):
i = 0 # числовое значение
while i < n: # цикл с предусловием
yield i # генерация значения
i += 1
for num in count_up_to(5): # цикл по элементам
print(num) # 0, 1, 2, 3, 4
# Генераторы — ленивые: значения создаются на лету
Генераторные выражения
# Круглые скобки — генератор (ленивый)
squares = (x**2 for x in range(10)) # последовательность чисел
print(squares) #
print(list(squares)) # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
# Квадратные — список (все сразу в памяти)
list_squares = [x**2 for x in range(10)] # последовательность чисел
# Эффективно для больших данных
sum(x**2 for x in range(1000000)) # сумма
Stateful-генераторы
def fibonacci():
a, b = 0, 1
while True: # цикл с предусловием
yield a # генерация значения
a, b = b, a + b
fib = fibonacci() # присваивание
[next(fib) for _ in range(10)] # [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
yield from — делегирование
def chain(*iterables):
for it in iterables: # цикл по элементам
yield from it # делегирование генератору
list(chain([1,2], [3,4])) # [1, 2, 3, 4]
Итераторы вручную
class Squares:
def __init__(self, n):
self.n = n # обращение к атрибуту экземпляра
self.i = 0 # обращение к атрибуту экземпляра
def __iter__(self):
return self # возврат значения
def __next__(self):
if self.i >= self.n: # условие
raise StopIteration # выброс исключения
result = self.i ** 2 # обращение к атрибуту экземпляра
self.i += 1 # обращение к атрибуту экземпляра
return result # возврат значения
list(Squares(5)) # [0, 1, 4, 9, 16]
itertools — инструменты для итераторов
import itertools # импорт модуля итераторов
# Бесконечные
itertools.count(10, 2) # 10, 12, 14, ...
itertools.cycle("ABC") # A, B, C, A, B, C, ...
itertools.repeat(42, 3) # 42, 42, 42
# Комбинаторика
itertools.permutations("ABC", 2) # AB, AC, BA, BC, CA, CB
itertools.combinations("ABC", 2) # AB, AC, BC
itertools.product("AB", "12") # A1, A2, B1, B2
# Полезные
itertools.chain([1,2], [3,4]) # 1, 2, 3, 4
itertools.zip_longest([1,2], [3,4,5]) # (1,3), (2,4), (None,5)
itertools.islice(range(100), 10) # итераторные функции
itertools.groupby(data, key_func) # итераторные функции
Генераторы vs списки: память
import sys # импорт системного модуля
list_comp = [x for x in range(1000000)] # последовательность чисел
gen_expr = (x for x in range(1000000)) # последовательность чисел
sys.getsizeof(list_comp) # ~8 MB (все элементы в памяти)
sys.getsizeof(gen_expr) # ~200 bytes (ленивый)