-
Notifications
You must be signed in to change notification settings - Fork 5
Python: генераторы последний рубеж Часть 1 Предварительные сведения Генераторы и сопрограммы
Dmitry Ponyatov edited this page Oct 5, 2019
·
10 revisions
- оператор
yield
определяет функцию-генератор
def countdown(n):
while n > 0:
yield n
n -= 1
- Вы обычно используете его для питания итерации
for x in countdown(10):
print('T-minus', x)
- Простая, но элегантная идея
- Объект генератора запускается в ответ на
next()
>>> c = countdown(3)
>>> c
<generator object countdown at 0x10064f900>
>>> next(c)
3
>>> next(c)
2
>>> next(c)
1
>>> next(c)
Traceback (most recent call last):
File "<stdin>", line 1, in ?
StopIteration
>>>
-
StopIteration
возникает при возврате из функции
- Генераторы как «итераторы» затеняют общую картину
- Есть намного больше того, что можно
yield
- Вложенные генераторы приводят к вычислительным конвейерам
- Аналогично трубам в Unix
- Невероятно полезные (см. предыдущие уроки)
-
yield
также может получать значение
def receiver():
while True:
item = yield
print('Got', item)
- Он определяет генератор, которому вы отправляете данные
recv = receiver()
next(recv) # должен быть первый вызов для перехода на yield
recv.send('Hello')
recv.send('World')
- Сопрограммы реализуют обработку в идеологии потоков данных
- Публикация / подписка, симуляция событий и т.д.
- Оператор
yield
определяет функцию-генератор
def generator():
...
... yield ...
...
- Достаточно присутствия
yield
в любом месте - Вызов функции создает экземпляр генератора
>>> g = generator()
>>> g
<generator object generator at 0x10064f120>
>>>
-
next(gen)
-- выполнение до следующегоyield
- возвращает полученный элемент данных (если он указан)
- Это единственная разрешенная операция на вновь созданном генераторе
- Примечание: То же, что и
gen.__next__()
-
gen.send(item)
-- отправить элемент данных в генератор
def generator():
...
item = yield
...
...
yield value
g = generator()
next(g) # необходимый стартовый вызов
value = g.send(item)
- Пробуждается на последнем
yield
, возвращает отправленное значение - Выполняется до следующего
yield
и отправляет значение
-
gen.close()
-- завершение генератора
def generator():
...
try:
yield
except GeneratorExit:
# Shutting down
...
g = generator()
next(g) # старт
g.close() # возбуждает исключение GeneratorExit
- возбуждает исключение
GeneratorExit
наyield
- Единственное разрешенное действие --
return
- Если исключение не перехватывается, генератор молча завершает работу
-
gen.throw(typ [, val [,tb]])
бросает исключение
def generator():
...
try:
yield
except RuntimeError as e:
...
...
yield val
g = generator()
next(g) # Advance to yield
val = g.throw(RuntimeError,'Broken')
- исключение попадает на
yield
-
throw()
возвращает следующее значение посланноеyield
(если оно указано)
-
StopIteration
возбуждается при выходе из генератора - Возвращаемое значение (если есть), передается как параметр исключения
- Примечание: поведение только в Python 3 (в Python 2 генераторы не могут возвращать значения)
-
yield from gen
делегация до вложенного подгенератора - Позволяет генераторам вызывать другие генераторы
- Операции выполняются в текущем
yield
- Возвращаемое значение (если есть) возвращается
- Цепочка итерируется вместе
def chain(x, y):
yield from x
yield from y
>>> a = [1, 2, 3]
>>> b = [4, 5, 6]
>>> for x in chain(a, b):
... print(x,end=' ')
...
1 2 3 4 5 6
>>> c = [7,8,9]
>>> for x in chain(a, chain(b, c)):
... print(x, end=' ')
...
1 2 3 4 5 6 7 8 9
>>>
- Определение генератора
def generator():
...
yield ...
...
return result
- Операции экземпляра генератора
gen = generator()
next(gen) # инициализация
gen.send(item) # послать данные
gen.close() # завершение
gen.throw(exc, val, tb) # бросить исключение в генератор
result = yield from gen # делегация итерации
- Используя их, вы можете сделать много полезных вещей
Python: генераторы последний рубеж Часть 2 А теперь что-то совсем другое