Ключове слово yield у Python: як воно працює
На профільних форумах розробників часто можна зустріти питання, яке стосується терміну yield у коді Python. Початківців цікавить, що таке yield, і як воно використовується. Давайте розглянемо його на кількох прикладах. Але спочатку розберемося з теорією.
У мові програмування Python за допомогою yield у функціях створюються генератори. Що таке генератор? За своєю суттю це особливий вид ітераторів, завдяки яким функції зберігають поточний стан між викликами і можуть по черзі повертати значення. Ітерація – це послідовний виклик та обробка елементів списку. Простіше кажучи, при обробці генератором object або інший елемент коду буде викликатись при кожному зверненні.
Як працює генератор
На відміну від звичних функцій, які використовують return для повернення значення та завершення роботи, генератори Python застосовують для цього yield, але при цьому зберігають свій стан між викликами. Якщо все ще незрозуміло, тоді завітайте до Stackoverflow. Там завжди є безліч прикладів, які допоможуть вам краще використовувати генератор.
За наявності в тілі програми слова yield, функція повертає значення та зупиняє своє виконання. При наступному виклику генератор може ітерувати виконання з того рядка, де він був призупинений. Тобто там, де він зустрів yield.
Щоб усе це краще зрозуміти, погляньмо на цей фрагмент:
def simple_generator(): yield 1 yield 2 yield 3 gen = simple_generator() print(next(gen)) # Вивід: 1 print(next(gen)) # Вивід: 2 print(next(gen)) # Вивід: 3
Тут бачимо функцію під назвою simple_generator. Вона по черзі повертає значення 1, 2 та 3 при кожному виклику next().
Які переваги дає yield для Python
Застосовуючи yield у своїх додатках, ви отримуєте дві очевидні переваги:
- Генератори обробляють об’єкти, що ітеруються, по черзі, а не завантажують всю послідовність чисел відразу і не зберігають значення в пам’яті. Тобто вони її не перевантажують.
- Почергове обчислення елементів більш оптимальне під час роботи з великими наборами даних.
Термін yield перетворює функцію на генератор. Його можна застосовувати для ітерації із збереженням проміжних станів.
Як використовувати yield для читання великого файлу рядково в Python
Давайте поглянемо на ще один приклад використання yield у Python. Завдяки йому ми зможемо прочитати великий файл. Практична перевага тут очевидна: ітератори починають обробляти код без необхідності завантаження пам’яті всього файлу відразу. Отже, ітератор не перевантажує пам’ять.
def read_large_file(file_path): with open(file_path, 'r') as file: for line in file: yield line.strip() # Застосування генератора file_path = 'large_text_file.txt' for line in read_large_file(file_path): # Обробляємо кожну строку файла print(line)
Пояснення коду:
Функція read_large_file(file_path) отримує шлях до файлу та відкриває його для читання. Далі вона виконує рядкову ітерацію у файлі за допомогою циклу for. Базовий варіант передбачає, що функція повертає всі рядки одночасно. Але тут вона використовує yield. Через це функція повертає лише один рядок за раз (без символу нового рядка в кінці).
Що стосується генератора, він створюється при виклику функції read_large_file. Оскільки тут присутній цикл for, кожен рядок файлу обробляється окремо. Якби ми мали справу зі справді великим файлом, то міг би виникнути ризик, що він не поміщається в оперативній пам’яті. Тут ми бачимо, як yield усуває подібну проблему.
Застосовуємо yield для багатозадачної обробки даних
Ось ще один, трохи складніший приклад використання yield. Тут він знадобиться для багатозадачної обробки даних без використання потоків чи асинхронного програмування. Використовуючи це ключове слово yield, ми виконуємо кілька завдань одночасно так само ефективно, як і за багатопотоковості.
У поданому нижче фрагменті ми реалізуємо диспетчер завдань, який керуватиме кількома процесами з можливістю перемикання між ними.
import time def task1(): count = 0 while True: count += 1 print(f"Task 1: {count}") yield # Повертаємо управління диспетчеру завдань def task2(): count = 0 while True: count += 1 print(f"Task 2: {count}") yield # Повертаємо управління диспетчеру завдань def task3(): count = 0 while True: count += 1 print(f"Task 3: {count}") yield # Повертаємо управління диспетчеру завдань def task_scheduler(tasks, max_cycles): # Ініціалізація генераторів завдань task_generators = [task() for task in tasks] for _ in range(max_cycles): for task_gen in task_generators: next(task_gen) # Переключаємось між завданнями time.sleep(0.1) # Затримка для демонстрації паралельної роботи # Приклад використання tasks = [task1, task2, task3] task_scheduler(tasks, max_cycles=5)
Як ви помітили, кожна з функцій: task1, task2 і task3 є нескінченним циклом роботи і виведення значень лічильника. Термін yield потрібен для тимчасового зупинення виконання завдання та повернення управління диспетчеру завдань.
Що стосується функції task_scheduler(tasks, max_cycles), то вона є диспетчером завдань, який ініціалізує генератори для кожного завдання і по черзі перемикається між об’єктами, що ітеруються, викликаючи next(task_gen) для кожного генератора. Для демонстрації паузи між перемикання завдань, імітуючи асинхронну обробку, вставлений time.sleep(0.1).
У списку tasks ми бачимо три завдання: task1, task2 та task3. Диспетчер робить 5 циклів перемикань, послідовно перемикаючи керування наступне завдання. У результаті маємо виникає генераторний вираз із послідовним значенням лічильників кожного завдання, що створює видимість паралельної роботи.
Фрагмент, який ви переглянули, може застосовуватися, наприклад, у комп’ютерній грі, де потрібно одночасно керувати кількома персонажами, або в програмі, де кілька завдань мають виконуватися по черзі з високою частотою перемикань.
Висновок
Застосування yield дає Python-програмісту кілька помітних переваг. По-перше, програма менше використовує пам’ятї. Замість завантаження всього файлу у пам’ять генератор обробляє рядки по черзі, що дає чималу економію ресурсів. По-друге, послідовна обробка рядків здатна прискорити виконання програми. Це особливо важливо, коли потрібно обробити файл або потокові дані. І, нарешті, третя перевага. Документація додатка, в якому застосовується цей термін, виглядає лаконічною та інтуїтивно зрозумілою, ніж аналогічний екземпляр із явним керуванням станом та використанням зовнішніх ітераторів.
Застосовувати yield рекомендується при роботі над проектами, де потрібно читати або обробляти дуже великі файли: логі дій користувачів, дані про транзакції і схожі системи.
Favbet Tech – це ІТ-компанія зі 100% украінською ДНК, що створює досконалі сервіси для iGaming і Betting з використанням передових технологіи та надає доступ до них. Favbet Tech розробляє інноваційне програмне забезпечення через складну багатокомпонентну платформу, яка здатна витримувати величезні навантаження та створювати унікальний досвід для гравців.
Сообщить об опечатке
Текст, который будет отправлен нашим редакторам: