Reputation: 307
I am writing a learning program in python, and I'm not getting the behavior I'm expecting. I am attempting to create a really basic tree with a class called node. Please don't punish me for having a crappy tree design, I'm just trying to learn the language.
Anyway, I'm expecting output like:
LEVEL1 0
LEVEL1 1
But, I'm getting
LEVEL1 0
LEVEL1 1
LEVEL1 0 ... LEVEL2 0
On the line where I do leaves[0].addLeaf
I really thought I would be calling a method of of one of the children leaves, but it appears that I am instead calling from the TOP leaf. Please help me understand.
Don't be tricked by the name traversePrint
. Nothing is being traversed, not yet anyway :(
#!/usr/bin/python
class node:
"""Something that can act like like leaves of a tree"""
leaves = []
def __init__(self, data=""):
self.data = data
def addLeaf(self, newNode="new"):
self.leaves.append(node(newNode))
def printLeafs(self):
for leaf in self.leaves:
print leaf.data
def getLeafs(self):
return self.leaves
def traversePrint(self):
for leaf in self.leaves:
print leaf.data
#for leaf in self.leaves:
# leaf.traversePrint()
top = node("TOP")
top.addLeaf("LEVEL1 0")
top.addLeaf("LEVEL1 1")
leaves = top.getLeafs()
leaves[0].addLeaf("LEVEL1 0 ... LEVEL2 0")
top.traversePrint()
Upvotes: 3
Views: 87
Reputation: 70602
Because you define leaves
at the class level, all instances of node
share a single leaves
list. I doubt that's what you intended. If you want each node
to have its own leaves
list, then move the assignment into __init__
instead:
# leaves = [] # REMOVE THIS LINE
def __init__(self, data=""):
self.data = data
self.leaves = [] # ADD THIS LINE
Then the output is:
LEVEL1 0
LEVEL1 1
and adding:
leaves[0].traversePrint()
prints:
LEVEL1 0 ... LEVEL2 0
Clear?
Upvotes: 3
Reputation: 17168
Your problem is that right now, leaves
is a class-level attribute. You want it to be an instance-level attribute, so that the list isn't shared between all the instances. See this SO question for some details on the difference.
Luckily, making leaves
an instance attribute is easy to do: remove the line leaves = []
and instead, change your __init__
method to include the line self.leaves = []
.
def __init__(self, data=""):
self.data = data
self.leaves = [] # Create a new list to hold this instance's children!
To see more clearly what's going on in your original code, try editing your addLeaf
method by adding print([leaf.data for leaf in self.leaves])
after you add the leaf. In your original code, this will print out:
['LEVEL1 0']
['LEVEL1 0', 'LEVEL1 1']
['LEVEL1 0', 'LEVEL1 1', 'LEVEL1 0 ... LEVEL2 0']
Of course, you only want one leaf to be shown on the third printout, because you're accessing a different node, but instead you got all three! This is because when the list is at the class level, all the instances of node
share the same leaves
list. When you move the list initialization inside the __init__
method, you see the expected results from your three addLeaf
calls:
['LEVEL1 0']
['LEVEL1 0', 'LEVEL1 1']
['LEVEL1 0 ... LEVEL2 0']
Upvotes: 4
Reputation: 88777
leaves
is a class attribute so all addLeaf
does is adds to that single attribute as all nodes are objects of class node
(btw rename it to Node)
What you want is per node attribute leaves, hence add it as instance attribute i.e. in __init__
add self.leaves = []
Upvotes: 2