Генераторы в Python - это мощный инструмент для обработки потоковых данных, поскольку они позволяют обрабатывать большие объемы данных по частям, не загружая все данные в память одновременно. Это особенно важно при работе с потоковыми данными, такими как логи, данные с сенсоров, или данные, получаемые по сети, где объем данных может быть неограниченным.
Основные принципы использования генераторов для потоковой обработки:
Ленивое вычисление: Генераторы вычисляют значения только тогда, когда они необходимы. Они не хранят все данные в памяти, а генерируют их "на лету" по требованию.
Итераторы: Генераторы - это итераторы. Они предоставляют интерфейс для последовательного доступа к данным с помощью функции next().
Функции-генераторы: Генераторы обычно реализуются в виде функций, которые используют ключевое слово yield. Когда функция-генератор встречает yield, она возвращает значение и приостанавливает свое выполнение, сохраняя свое состояние. При следующем вызове next() функция возобновляет выполнение с места, где она остановилась.
Пример: Чтение большого файла построчно с использованием генератора:
def read_file_lines(filename):
    """Генератор, который построчно читает файл."""
    with open(filename, 'r') as f:
        for line in f:
            yield line.strip()  # Убираем пробельные символы в начале и конце строки
# Использование генератора
for line in read_file_lines('large_file.txt'):
    # Обработка каждой строки
    print(line)
  В этом примере функция read_file_lines является генератором. Она построчно читает файл и возвращает каждую строку с помощью yield.  При этом в память не загружается весь файл целиком, а только одна строка за раз, что позволяет эффективно обрабатывать очень большие файлы.
Пример: Обработка потока данных из сети:
import socket
def receive_data(host, port):
    """Генератор, который получает данные из сокета."""
    with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
        s.bind((host, port))
        s.listen()
        conn, addr = s.accept()
        with conn:
            print(f"Connected by {addr}")
            while True:
                data = conn.recv(1024) # Читаем порцию данных (1024 байта)
                if not data:
                    break # Выход из цикла, если соединение закрыто
                yield data
# Использование генератора
for chunk in receive_data('127.0.0.1', 65432):
    # Обработка полученного куска данных
    print(f"Received: {chunk.decode()}") # Декодируем байты в строку
  Здесь генератор receive_data получает данные по сети порциями (chunk) и передает их для обработки. Это позволяет обрабатывать потоковые данные без необходимости буферизации всего потока в памяти.
Преимущества использования генераторов для потоковой обработки:
Экономия памяти: Не загружаются все данные в память сразу, что особенно важно для больших объемов данных.
Улучшенная производительность: Обработка начинается сразу после получения первой порции данных, без ожидания завершения чтения всего потока.
Более читаемый и поддерживаемый код: Генераторы позволяют создавать более компактный и выразительный код для обработки потоковых данных.
Возможность композиции: Генераторы легко комбинировать, создавая сложные цепочки обработки данных.
Заключение: Генераторы предоставляют элегантный и эффективный способ обработки потоковых данных в Python. Они позволяют экономить память, улучшать производительность и писать более чистый и понятный код.