1

I'm trying to wrap my head around python generators and as a result, I'm trying to print infinitely nested objects using yield, but I find that I still get problems with blowing out the stack. Ideally, I'd like to be able to yield and print each item as it comes along but I can't figure out what I'm doing wrong:

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
SophieB
  • 25
  • 3
  • 2
    If you read the traceback, you will note that the error is caused by `print t`, therefore via `Parent.__str__`, not `__iter__`. You have set this up yourself - `p1` is a child of `p2`, which is a child of `p1`, which is a child of `p2`, which... – jonrsharpe Oct 12 '14 at 14:53

2 Answers2

1

The error in your code, as noted by jonrsharpe, is due to the __str__ function, which tries to return:

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

You probably mean:

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

Also, __iter__ should be a generator function. Generator functions need to contain a loop in order to continually produce values. So it should be something like:

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

With the modifications, your code prints endless lines of child has child.

See also What does the yield keyword do in Python? for more information about generator functions.

Community
  • 1
  • 1
parchment
  • 4,063
  • 1
  • 19
  • 30
0

The infinite recursion is happening at __str__ function. It has nothing to do with the __iter__ function.

when you do print t, it executes t._child.__str__ which in turn executes t._child._child.__str__ and so forth.

try changing the __str__ function definition to something simple like return self._name and you won't get a recursion depth exceeded error

srj
  • 9,591
  • 2
  • 23
  • 27