2013-08-01 4 views
1

Я смотрел http://www.dabeaz.com/coroutines/, который я нахожу очень интересным, но в примере есть поведение, которое я не понимаю.Значение теряется в генераторе python/coroutine

В bogus.py например, сообщил здесь

# bogus.py 
# 
# Bogus example of a generator that produces and receives values 
def countdown(n): 
    print "Counting down from", n 
    while n >= 0: 
     newvalue = (yield n) 
     # If a new value got sent in, reset n with it 
     if newvalue is not None: 
      n = newvalue 
     else: 
      n -= 1 

# The holy grail countdown 
c = countdown(5) 
for x in c: 
    print x 
    if x == 5: 
     c.send(3) 

Последовательность чисел генерируемого 5, 2, 1, 0, и я не могу понять, где число 3 ушло: после send(3), переменного n правильно установлен, но при втором выполнении yield, это похоже на то, что значение 3 просто не получено для цикла for.

Может кто-нибудь разъяснить мне, почему это происходит?

ответ

3

3 был отправлен с .send(), но отказался. Генератор производит 5, 3, 2, 1, 0; но потому, что 3 возвращается на вызов .send(), вы не видите это значение. Цикл for никогда не увидит его.

Что происходит:

  • первый раз цикл for вызывает next() на генератор, код продвигается до 5 не дали.
  • x == 5True, поэтому c.send(3) называется. Код продвигается через функцию генератора, а newvalue - 3.
  • Генератор не пауза там, теперь он имеет контроль. Генератор проходит через цикл while и возвращается к выражению (yield n). 3. Он становится возвращаемым значением для c.send(3). Возвращаемое значение здесь отбрасывается.
  • Цикл for продолжается, снова вызывает next(). Генератор снова продолжается с yield, возвращая None, петли округляются до n -= 1 и дают 2.
  • Цилиндр for продолжает называть next() на генераторе, 1 и 0 даны, генератор заканчивается.

Qouting из generator.send() documentation:

Резюме исполнения и «посылает» значение в функцию генератора. Аргумент value становится результатом текущего выражения yield. Метод send() возвращает следующее значение, полученное генератором, или повышает StopIteration, если генератор выходит, не давая другого значения.

Emphasis mine.

+0

Отлично, спасибо! Я пропустил факт, в вашем третьем пункте, что 'send' на самом деле похож на' next' и, следовательно, имеет возвращаемое значение, исходящее из 'yield'. – AkiRoss

+1

Добавление из спецификации ([pep-0342] (http://www.python.org/dev/peps/pep-0342/)) 2. Добавить новый метод send() для генераторов-итераторов, который возобновляет генератор и «отправляет» значение, которое становится результатом текущего выражения yield. Метод send() возвращает следующее значение, полученное генератором, или вызывает StopIteration, если генератор выходит, не давая другого значения. –

+0

Я немного смущен тоже шагом3. , когда n == 5, выведите 5 и распечатайте его. Затем c.send (3), чтобы вызвать выход 3 в качестве возвращаемого значения обратно в c.send() и присвоить значение 3 newvalue Если мой оператор True, то почему, когда n == 3 для продолжения следующего чтобы получить значение newvalue = (выход n), не уступая значению n, но говоря, что значение n == 3 было отброшено? – rickhau