1

Is it possible to iterate though an object that contains a list of objects.

For example, I have the following class

Class Page(object)

    def __init__(self, name):

        self.name = name
        self.pages = []

I then create a new Page object and add other page objects to it.

page = Page('FirstPage')

apagepage = Page('FirstChild')

anotherpagepage = Page('SecondChild')

apagepage.pages.append(Page('FirstChildChild'))

apagepage.pages.append(Page('SecondChildChild'))

page.pages.append(apagepage)

page.pages.append(anotherpagepage)

What I would like to do is

for thispage in page:
    print thispage.name

And get the following output

FirstPage
FirstChild
SecondChild
FirstChildChild
SecondChildChild

So I get all the 1st level, then the 2nd, then the 3rd.

However, the following output would be find as well

FirstPage
FirstChild
FirstChildChild
SecondChildChild
SecondChild
1
  • 2
    You should look for questions about flattening a list Commented Oct 23, 2012 at 4:23

4 Answers 4

3

You can define a __str__

from itertools import chain

class Page(object):
    def __init__(self, name):
        self.name = name
        self.pages = []
    def __str__(self):
        return "\n".join(chain([self.name], map(str, self.pages)))

then you can just print page

Alternatively you can define an iterator if you wish to use your the for loop

class Page(object):
    def __init__(self, name):
        self.name = name
        self.pages = []
    def __iter__(self):
        yield self
        for page in self.pages:
            for i in page:
                yield i
Sign up to request clarification or add additional context in comments.

4 Comments

__repr__ should strive to return a representation that can be evaluated to get the original object. You should instead use __str__ for human-readable representations like this.
you could traverse a tree-like object in different ways. Some might prefer that iter(page) would return only immediate children and use explicit page.walk() for recursive traversals.
@J.F.Sebastian If I'm understanding your correctly, could I use iter to iterate all the direct children. And then some how do a walk to iterate though all the children. That would be just like the os.path.walk function. I'm not sure if this will help me or not but I would be very interested in learning how to do this. Thanks
@nerd: I've posted answer to show what I mean
1

Do it recursively:

class Page(object):
    def __init__(self, name):
        self.name = name
        self.pages = []

    def __iter__(self):
        for p in self.get_children_pages(self):
            yield p

    def get_children_pages(self, start_page):
        result = [start_page.name]
        for this_page in start_page.pages:
            result.extend(self.get_children_pages(this_page))
        return result


>>>>for p in page:
....    print p

FirstPage
FirstChild
FirstChildChild
SecondChildChild
SecondChild

Comments

0

Do it recursively

def print_all_pages(page):
    print page.name
    if len(page.pages) == 0 then:
        return
    else:
        for child_page in page.pages:
            print_all_pages(child_page)

def print_pages(pages_collection):
    for page in pages_collection:
        print_all_pages(page)

2 Comments

1. I don't think this is what OP wants 2. your code does not actually work. You may want check the exit condition
@KayZhu - fixed syntax errors, my b. Seems that it is what he was looking for though... can't say for sure, of course.
0
class Page(object):
    def __init__(self, name, pages=None):
        self.name = name
        self.pages = pages if pages is not None else []
    def __iter__(self):
        return iter(self.pages) # only immediate children
    def walk(self, topdown=True): # all pages recursively
        if topdown:
            yield self
        for page in self:
            yield from page.walk(topdown)
        if not topdown:
            yield self

You can replace yield from on Python <3.3 with:

for subpage in page.walk(topdown):
    yield subpage

in this case.

Example

page = Page('FirstPage', [
        Page('FirstChild', [
                Page('FirstChildChild'),
                Page('SecondChildChild'),
                ]),
        Page('SecondChild'),
        ])

for p in page.walk():
    print(p.name)

Output

FirstPage
FirstChild
FirstChildChild
SecondChildChild
SecondChild

1 Comment

Thank you. This solution is both ideal and elegant.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.