Python-эквивалент продолжения с Ruby - PullRequest
7 голосов
/ 23 ноября 2008

Что является эквивалентом 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: Основы на основе продолжений

Ответы [ 5 ]

5 голосов
/ 23 ноября 2008

В цитируемой вами статье содержится ссылка на продолжений, сделанных простыми и иллюстрированными в разделе Ресурсы, в которых говорится о продолжениях на языке Python.

2 голосов
/ 01 декабря 2010

Существует много слабых обходных путей, которые работают в особых случаях (см. Другие ответы на этот вопрос), но нет языковой конструкции Python, эквивалентной callcc или которая может использоваться для создания чего-то, эквивалентного callcc.

Возможно, вы захотите попробовать Stackless Python или расширение greenlet Python, оба из которых предоставляют сопрограммы, на основе которых можно создавать одноразовые продолжения, но это еще слабее, чем callcc Руби (который обеспечивает полное продолжение).

2 голосов
/ 24 ноября 2008

Использование 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)
2 голосов
/ 23 ноября 2008

взгляните на оператор yield для создания генераторов.

Я не говорю по-русски, но похоже, что вы ищете это:

def loop():
    for i in xrange(1,5):
        print i
        if i == 2:
            yield


for i in loop():
    print "pass"

Edit: я понимаю, что это в основном специализация реальных продолжений, но этого должно быть достаточно для большинства целей. Используйте yield для возврата продолжения и сообщение .next() на генераторе (возвращаемое простым вызовом loop()) для повторного ввода.

0 голосов
/ 23 ноября 2008
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()
...