Справочник Python

Полное руководство по языку на русском

Генераторы и итераторы

Генераторные функции

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 (ленивый)