2014-10-12 3 views
1

Я пытаюсь обернуть голову генераторами python, и в результате я пытаюсь напечатать бесконечно вложенные объекты с использованием yield, но я обнаружил, что у меня все еще возникают проблемы с выдуванием стека. В идеале, я хотел бы быть в состоянии дать и печатать каждый элемент, как он приходит, но я не могу понять, что я делаю неправильно:Python бесконечная рекурсия с генераторами

class Parent:  
    def __init__(self, name, child=None): 
     self._name = name 
     self._child = child 

    def get_name(self): 
     return self._name 

    def get_child(self): 
     return self._child 

    def set_child(self, child): 
     self._child = child 

    def __iter__(self): 
     next_child = self._child.get_child() 
     if not next_child: 
      raise StopIteration    
     else: 
      self._child = next_child 
      yield next_child 

    def __str__(self): 
     return "%s has %s" % (self._name, self._child) 

if __name__ == '__main__': 
    p1 = Parent("child") 
    p2 = Parent("child", p1) 
    p1.set_child(p2) 

    for t in p1: 
     print t 
+2

Если вы читали отслеживающий, вы заметите, что ошибка вызвана 'печати Т *, поэтому через 'Parent .__ str__', а не' __iter__'. Вы сами установили это - 'p1' является дочерним элементом' p2', который является дочерним элементом 'p1', который является дочерним элементом' p2', который ... – jonrsharpe

ответ

1

Ошибка в коде, как отмечает jonrsharpe , связано с функцией __str__, которая пытается вернуть:

child has child has child has child has child has ... 

Вы, наверное, имели в виду:

def __str__(self): 
    return "%s has %s" % (self._name, self._child.get_name()) 
    # return 'child has child' 

Кроме того, __iter__ должен быть функцией генератора. Функции генератора должны содержать цикл, чтобы постоянно создавать значения. Так что это должно быть что-то вроде:

def __iter__(self): 
    next_child = self._child.get_child() 
    while next_child:    
     yield next_child 
     next_child = next_child.get_child() 
    # When the function ends, it will automatically raise StopIteration 

С изменениями, ваш код печатает бесконечные линии child has child.

См. Также What does the yield keyword do in Python? для получения дополнительной информации о функциях генератора.

0

Бесконечная рекурсия происходит при __str__ функции. Он не имеет ничего общего с функцией __iter__.

если вы делаете print t, он выполняет t._child.__str__, который, в свою очередь, выполняет t._child._child.__str__ и так далее.

попробуйте изменить определение __str__ функции на что-то простое, как return self._name и вы не получите глубину рекурсии превышена ошибка