Итераторы
Объект итерируемый, если у него есть метод __iter__. Итератор дополнительно реализует __next__:
numbers = [1, 2, 3]it = iter(numbers)print(next(it))print(next(it))print(next(it))Когда элементы кончаются, next вызывает StopIteration — именно так цикл for понимает, что пора остановиться.
Собственный итератор:
class Countdown: def __init__(self, start): self.current = start def __iter__(self): return self def __next__(self): if self.current <= 0: raise StopIteration value = self.current self.current -= 1 return valuefor n in Countdown(3): print(n)Генераторы
Функция с yield возвращает генератор — ленивый итератор:
def countdown(start): while start > 0: yield start start -= 1for n in countdown(3): print(n)Состояние функции сохраняется между вызовами next. Значения вычисляются по требованию, что позволяет работать с огромными или бесконечными последовательностями:
def naturals(): n = 0 while True: yield n n += 1gen = naturals()print(next(gen), next(gen), next(gen))Генераторные выражения
total = sum(x ** 2 for x in range(1_000_000))В отличие от списка, список значений в памяти не создаётся.
yield from
def chain(*iterables): for it in iterables: yield from itprint(list(chain([1, 2], "ab")))Модуль itertools
from itertools import count, islice, chain, product, permutations, combinations, groupbyprint(list(islice(count(10), 3)))print(list(chain([1], [2, 3])))print(list(product("ab", repeat=2)))print(list(permutations([1, 2, 3], 2)))print(list(combinations([1, 2, 3], 2)))Замыкания
def multiplier(factor): def multiply(x): return x * factor return multiplydouble = multiplier(2)print(double(5))Декораторы
Декоратор — функция, которая принимает функцию и возвращает новую:
import functoolsimport timedef timer(func): @functools.wraps(func) def wrapper(*args, **kwargs): start = time.perf_counter() result = func(*args, **kwargs) elapsed = time.perf_counter() - start print(f"{func.__name__}: {elapsed:.4f} с") return result return wrapper@timerdef work(n): return sum(range(n))work(1_000_000)Запись @timer эквивалентна work = timer(work). Декоратор functools.wraps сохраняет имя и документацию исходной функции.
Декоратор с параметрами
import functoolsdef repeat(times): def decorator(func): @functools.wraps(func) def wrapper(*args, **kwargs): result = None for _ in range(times): result = func(*args, **kwargs) return result return wrapper return decorator@repeat(3)def hello(): print("hello")hello()Готовые декораторы
from functools import lru_cache, cache@lru_cache(maxsize=None)def fib(n): if n < 2: return n return fib(n - 1) + fib(n - 2)print(fib(80))Задания
- Напишите генератор чисел Фибоначчи, выдающий значения до заданного предела.
- Реализуйте декоратор
retry, повторяющий вызов функции при исключении заданное число раз. - Прочитайте большой файл построчно с помощью генератора, отфильтровав строки по условию.
