Щоб зрозуміти, що робить 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 0xb7555c34="" at="" creategenerator="" object="">
>>> 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 0xb754f1dc="" at="" object="">
>>> 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)]
```</itertools.permutations></generator>
Ще немає коментарів