0

I have a class where each instance is basically of a bunch of nested lists, each of which holds a number of integers or another list containing integers, or a list of lists, etc., like so:

class Foo(list):
    def __init__(self):
        self.extend(
            list(1), list(2), list(3), range(5), [range(3), range(2)]
            )

I want to define a method to walk the nested lists and give me one integer at a time, not unlike os.walk. I tried this:

def _walk(self):
    def kids(node):
        for x in node:
            try:
                for y in kids(x):
                    yield y
            except TypeError:
                yield x
    return kids(x)

But it immediately raises a stopiteration error. If I add a print statement to print each "node" in the first for loop, the function appears to iterate over the whole container in the way I want, but without yielding each node. It just prints them all the first time I call next on the generator.

I'm stumped. Please help!

twneale
  • 2,836
  • 4
  • 29
  • 34
  • is x an instance variable of your class (as well as a local variable)? – Gordon Gustafson Aug 30 '10 at 17:08
  • 1
    `return kids(x)` will give a `NameError`! – Jochen Ritzel Aug 30 '10 at 17:10
  • 1
    `self.extend(list(1), list(2), list(3), range(5), [range(3), range(2)])` makes no sense either. If you want to write pseudocode, that's fine, but don't make it look like real Python code! – Jochen Ritzel Aug 30 '10 at 17:12
  • 2
    Anyways, a very wild guess on what `kids` is supposed to do: Flatten a list of lists, like http://stackoverflow.com/questions/2158395/flatten-an-irregular-list-of-lists-in-python – Jochen Ritzel Aug 30 '10 at 17:18
  • Yeah, whoops, that code was gibberish. x was a typo--should have been self. Don't want to flatten nested lists though--don't want everything in memory. Just want one at a time. – twneale Aug 30 '10 at 21:12

2 Answers2

1

It works if you change return kids(x) to return kids(self)

Wai Yip Tung
  • 18,106
  • 10
  • 43
  • 47
1

Here's a function that is a simpler version of your _walk method that does what you want on an arbitrary iterable. The internal kids function is not required.

def walk(xs):
    for x in xs:
        try:
            for y in walk(x):
                yield y
        except TypeError:
            yield x

This could be trivially adapted to work as a method on your Foo object.

Will McCutchen
  • 13,047
  • 3
  • 44
  • 43