Що таке генератор і ключове слово yield
Щоб зрозуміти, що робить yield, необхідно знати, що таке генератори, а перед генераторами йдуть ітератори.
Ітератори
Коли ви створюєте список, ви можете прочитати його елементи один за одним. Це називається ітерація:
>>> mylist = [1, 2, 3]
>>> for i in mylist:
... print(i)
1
2
3
В даному випадку, mylist є ітерованим об’єктом. При створенні списку за допомогою спискових виразів, він також буде ітерованим.
>>> mylist = [x*x for x in range(3)]
>>> for i in mylist:
... print(i)
0
1
4
Все, до чого можна застосувати for … in … : є ітерованими об’єктами: lists, strings, files…
Ітерації зручно використовувати, тому що, ви можете прочитати дані багато разів, але вони зберігаються в пам’яті й інколи це призводить до зайвих затрат ресурсів.
Генератори
Генератори це ті ж самі ітератори, але дані ви можете проітерувати лише один раз. Це тому, що вони не зберігаються в пам’яті, а генеруються на льоту:
>>> mygenerator = (x*x for x in range(3))
>>> for i in mygenerator:
... print(i)
0
1
4
>>> for i in mygenerator:
... print(i)
>>>
Генератори використовують такий же синтаксис, як і спискові вирази, окрім дужок: ( ) замість [ ]. Ви не можете виконати for i in mygenerator вдруге, оскільки генератор може бути використаний лише раз: він вираховує 0, тоді видаляє його з пам’яті і обчислює 1, видаляє його, обчислює 4 і також його видаляє, один за одним.
Yield
Yield це ключове слово, що використовується подібно до return, однак замість функції виступає генератор.
>>> def createGenerator():
... mylist = range(3)
... for i in mylist:
... yield i*i
...
>>> mygenerator = createGenerator() # створюємо генератор
>>> print(mygenerator) # mygenerator - об'єкт!
<generator object createGenerator at 0xb7555c34>
>>> for i in mygenerator:
... print(i)
0
1
4
Цей приклад недоцільний, але він чудово демонструє зручність використання, коли вам необхідно лише прочитати дані, які повертає функція.
Щоб опанувати yield, ви повинні зрозуміти, що, коли ви викликаєте функцію, код, написаний в тілі функції не виконується. Функція лише повертає об’єкт генератора.
Ваш код буде викликатися кожного разу, коли for буде звертатися до генератора.
Тепер найважче:
Коли for перший раз викликає об’єкт генератора з функції, вона виконає код функції від початку і до слова yield - тоді поверне перше значення ітерації. Кожен наступний виклик буде відбуватися ще одна ітерація циклу і буде повертатися наступне значення. І так поки не закінчаться значення.
Генератор вважається порожнім, як тільки при виконанні коду не зустрінеться yield. Причиною може бути кінець циклу, або не виконання умови if … else
Itertools – ваш кращий друг
Модуль Itertools містить спеціальні функції для управління ітерованими об’єктами. Можливо бажаєте продублювати генератор? З’єднати два генератори? Згрупувати значення вкладених списків в одну лінію?
Тоді import itertools.
Для прикладу, можливі результати кінних гонок з 4 кіньми:
>>> horses = [1, 2, 3, 4]
>>> races = itertools.permutations(horses)
>>> print(races)
<itertools.permutations object at 0xb754f1dc>
>>> print(list(itertools.permutations(horses)))
[(1, 2, 3, 4),
(1, 2, 4, 3),
(1, 3, 2, 4),
(1, 3, 4, 2),
(1, 4, 2, 3),
(1, 4, 3, 2),
(2, 1, 3, 4),
(2, 1, 4, 3),
(2, 3, 1, 4),
(2, 3, 4, 1),
(2, 4, 1, 3),
(2, 4, 3, 1),
(3, 1, 2, 4),
(3, 1, 4, 2),
(3, 2, 1, 4),
(3, 2, 4, 1),
(3, 4, 1, 2),
(3, 4, 2, 1),
(4, 1, 2, 3),
(4, 1, 3, 2),
(4, 2, 1, 3),
(4, 2, 3, 1),
(4, 3, 1, 2),
(4, 3, 2, 1)]
682 9


Коментарі:
2
OlegWock
Дуже гарний переклад. Q-Bart, ти молодець :3
2
Q-Bart
OlegWock, дякую, стараюсь
1
vvvityaaa
Дуже хороша стаття і якісний переклад. Так тримати))