Python-эквивалент продолжений с Ruby
-
10-07-2019 - |
Вопрос
Каков эквивалент Python следующего кода в Ruby?
def loop
cont=nil
for i in 1..4
puts i
callcc {|continuation| cont=continuation} if i==2
end
return cont
end
> c=loop
1
2
3
4
> c.call
3
4
Ссылка: Секреты успеха облегченной разработки, часть 9:Фреймворки на основе продолжений
Решение
В цитируемой вами статье содержится ссылка на продолжения, упрощенные и иллюстрированные в разделе Ресурсы, в котором говорится о продолжениях на языке Python.
Другие советы
взгляните на yield заявление для генераторов.
Я не говорю по-русски, но похоже, что ты ищешь это:
def loop():
for i in xrange(1,5):
print i
if i == 2:
yield
for i in loop():
print "pass"
Редактировать: я понимаю, что это в основном специализация реальных продолжений, но этого должно быть достаточно для большинства целей. Используйте yield
, чтобы вернуть продолжение и сообщение .next ()
в генераторе (возвращаемое простым вызовом loop ()
) для повторного входа. р>
С использованием generator_tools
(установить:'$ easy_install generator_tools
'):
from generator_tools import copy_generator
def _callg(generator, generator_copy=None):
for _ in generator: # run to the end
pass
if generator_copy is not None:
return lambda: _callg(copy_generator(generator_copy))
def loop(c):
c.next() # advance to yield's expression
return _callg(c, copy_generator(c))
if __name__ == '__main__':
def loop_gen():
i = 1
while i <= 4:
print i
if i == 2:
yield
i += 1
c = loop(loop_gen())
print("c:", c)
for _ in range(2):
print("c():", c())
Выход:
1
2
3
4
('c:', <function <lambda> at 0x00A9AC70>)
3
4
('c():', None)
3
4
('c():', None)
Есть много слабых обходных путей, которые работают в особых случаях (см. другие ответы на этот вопрос), но нет языковой конструкции Python, которая эквивалентна callcc
или которая может использоваться для создания чего-то эквивалентного в callcc
.
Вы можете попробовать Stackless Python или greenlet Расширение Python, оба из которых предоставляют сопрограммы, на основе которых можно создавать продолжения одним выстрелом, но это все же слабее, чем в callcc Руби
(который предоставляет полные продолжения).
def loop():
def f(i, cont=[None]):
for i in range(i, 5):
print i
if i == 2:
cont[0] = lambda i=i+1: f(i)
return cont[0]
return f(1)
if __name__ == '__main__':
c = loop()
c()