3. «Подпрограммы — это частные случаи более общих программных
компонентов, называемых сопрограммами. В противоположность
несимметричной связи между главной программой и
подпрограммой, между сопрограммами, которые вызывают одна
другую, существует полная симметрия.»
«Искусство программирования» Д. Кнут
«A coroutine is similar to a procedure and a generator is similar to a
function. The principle difference between these program units and
procedures/functions is that the call/return mechanism is different.
Coroutines are especially useful for multiplayer games and other
program flow where sections of code "take turns" executing. Generators,
as their name implies, are useful for generating a sequence of values; in
many respects generators are quite similar to HLA’s iterators without all
the restrictions of the iterators »
«The Art of Assembly Language» by Randall Hyde
8. Disclaimers
Coroutines — одна из наиболее неясных
особенностей Python
Асинхронность и конкурентность — одни из
наиболее сложных тем в computer science
Основной фундамент заложен в 60-80 годы, но
работа в этом направлении была закончена в
пользу других альтернатив (threads,
continuations...)
10. Итерируемые объекты (iterables) - объект,
который реализует метод __iter__(),
возвращающий итератор.
Итератор — объект, реализующие метод
__next__()
11. class Letter:
def __init__(self):
self.current = 'a'
def __next__(self):
if self.current > 'd':
raise StopIteration
result = self.current
self.current = chr(ord(result)+1)
return result
def __iter__(self):
return self
12. >>> iletter = Letter()
>>> letter = iter(iletter)
>>> letter.__next__()
'a'
>>> letter.__next__()
'b'
>>> next(letter)
'c'
>>> next(letter)
'd'
>>> next(letter)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "letter.py", line 7, in __next__
raise StopIteration
StopIteration
>>> letter = Letter()
>>> for l in letter:
... print(l)
...
a
b
c
d
>>> sum(letter)
0
13. For Statements
letter = Letter()
>>> i = letter.__iter__()
>>> try:
while True:
item = i.__next__()
print(item)
except StopIteration:
pass
a
b
c
d
14. PEP 255 -- Simple Generators
Authors:
Neil Schemenauer <nas at arctrix.com>,
Tim Peters <tim.peters at gmail.com>,
Magnus Lie Hetland <magnus at hetland.org>
Created: 18-May-2001
Python 2.2
15. >>> def letters_generator():
current = 'a'
while current <= 'd':
yield current
current = chr(ord(current)+1)
>>> for letter in letters_generator():
print(letter)
a
b
c
d
16. def countdown(n):
print("Counting down from", n)
while n > 0:
yield n
n -= 1
>>> x = countdown(10)
>>> x
<generator object countdown at 0x7fe8f9cd5318>
>>> next(x)
Counting down from 10
10
>>>
17.
18. Генераторы
Прострой способ создания итераторов
,Простой синтаксис добавлено только
yieldключевое слово
Запоминаются состояния между вызовами
IconСтащили идею из
19. PEP 342 Coroutine via Enhanced Generators
Authors: Guido van Rossum, Phillip J. Eby
Created: 10-May-2005
Python 2.5
PEP 288, Generators Attributes and Exceptions
(Raymond Hettinger)
PEP 325, Resource-Release Support for Generators
(Samuele Pedroni)
20. Что добавилось
1. (yield) statement:
value = (yield)
2. send()
3. throw()
4. close()
5. Вызов close() сборщиком мусора
6. Разрешено использование yield внутри
try/finally блоков
21. >>> def match(pattern):
print('Ищем ' + pattern)
try:
while True:
s = (yield)
if pattern in s:
print(s)
except GeneratorExit:
print("=== Done ===")
>>> m = match("runnts")
>>> m.__next__()
Ищем runnts
>>> m.send("А про rannts - все очень просто.")
А про rannts - все очень просто.
>>> m.send("Две n - географическая привязка")
>>> m.send("rant - тирады, пустословие, помпезные речи,
бахвальство, декламация и шумная проповедь")
>>> m.close()
=== Done ===
27. PEP 380 Syntax for Delegating to a Subgenerator
Authors: Gregory Ewing
Created: 13-Feb-2009
Python 3.3
28. Новый оператор
RESULT = yield from EXPR
Теперь вместо
for v in g:
yield v
Можно писать
yield from g
29. def writer():
while True:
w = (yield)
print('>> ', w)
def writer_wrapper(coro):
pass
w = writer()
wrap = writer_wrapper(w)
wrap.send(None)
for i in range(4):
wrap.send(i)
# Expected result
>> 0
>> 1
>> 2
>> 3
30. def writer_wrapper(coro):
coro.send(None) # prime the coro
while True:
try:
x = (yield) # Capture the value that's sent
coro.send(x) # and pass it to the writer
except StopIteration:
pass
или
def writer_wrapper(coro):
yield from coro