Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Convert recursive generator object to list

I have been trying to implement a simple tree structure in Python. A tree begins at a single "root" node which has children, each of its children may have own children and so forth.

Now, I want to print the names of all nodes of the tree, that is I want to convert it to a list. I sought to employ recursiveness but unfortunately yielding recursively returns a sub-tree of generator objects which I cannot convert to nodes.

Could somebody help me and point out what I am doing wrong here please?

class Node:

  def __init__(self,name):
    self.name = name
    self.children = []
    self.parent = None


  def appendChild(self,child):
    self.children.append(child)
    if child is not None:
      child.parent = self


  def listChildren(self):
    yield self
    for child in self.children:
      yield child.listChildren()
    raise StopIteration

# test
r = Node("root")

n = Node("name")
r.appendChild(n)
n.appendChild(Node("name2"))
n.appendChild(Node("name3"))

c = Node("child")
n.appendChild(c)
c.appendChild(Node("child2"))
c.appendChild(Node("child3"))

r.appendChild(Node("name4"))
r.appendChild(Node("name5"))
r.appendChild(Node("name6"))

for child in r.listChildren():
    print child.name

Output:

Traceback (most recent call last):
  File "C:/Users/User/Documents/TreeNode.py", line 40, in <module>
    print child.name
AttributeError: 'generator' object has no attribute 'name'

A generator is supposed to be called when it is being iterated over, but in my case every child in r.listChildren() is, in turn, a generator object. If this is a design flaw, then I would have to look for another way of generating a list of node names.

Thank you in advance!

like image 994
Pavlo Dyban Avatar asked May 24 '26 07:05

Pavlo Dyban


1 Answers

child.listChildren() will return a generator object and not the actual children. So you probably want to do something like:

def listChildren(self):
  yield self
  for child in self.children:
    for c in child.listChildren():
      yield c
  raise StopIteration # PS: you don't need to do that explicitly

Alternatively if you use Python 3.3 you could do:

def listChildren(self):
  yield self
  for child in self.children:
    yield from child.listChildren()
like image 51
Qlaus Avatar answered May 25 '26 20:05

Qlaus