views:

99

answers:

3

Hi,

I'm new to Python and it's OOP stuff and can't get it to work. Here's my code:

class Tree:

    root = None;
    data = [];

    def __init__(self, equation):
        self.root = equation;

    def appendLeft(self, data):
        self.data.insert(0, data);

    def appendRight(self, data):
        self.data.append(data);

    def calculateLeft(self):
        result = [];
        for item in (self.getLeft()):
            if (type(item) == type(self)):
                data = item.calculateLeft();
            else:
                data = item;
            result.append(item);
        return result;

    def getLeft(self):
        return self.data;

    def getRight(self):
        data = self.data;
        data.reverse();
        return data;

tree2 = Tree("*");
tree2.appendRight(44);
tree2.appendLeft(20);

tree = Tree("+");
tree.appendRight(4);
tree.appendLeft(10);
tree.appendLeft(tree2);

print(tree.calculateLeft());

It looks like tree2 and tree are sharing list "data"?

At the moment I'd like it to output something like [[20,44], 10, 4], but when I

tree.appendLeft(tree2) 

I get RuntimeError: maximum recursion depth exceeded, and when i even won't appendLeft(tree2) it outputs [10, 20, 44, 4] (!!!). What am I missing here? I'm using Portable Python 3.0.1.

Thank you

+8  A: 

The problem is that you've declared data as a class variable, so all instances of the class share the same list. Instead, put self.data = [] in your __init__.

Also, get rid of all those semicolons. They are unnecessary and clutter up your code.

Ned Batchelder
+1 for answer plus semicolons remark
catchmeifyoutry
Thanks, did't expect, that declaring them as class variable would make them 'global'. Finally can finish my homework now :).
Mikk
Writing semicolons at the end of the line is just habit form java and PHP, will remove them :)
Mikk
+3  A: 

Move root and data into the definition of __init__ . As it stands, you have them defined as class attributes. That makes them shared among all instances of the Tree class. When you instantiate two Trees (tree and tree2), they both share the same list accessed with self.data. To make each instance have its own instance attribute, you must move the declaration into the __init__ function.

def __init__(self, equation):
    self.root = equation
    self.data = []

Also, use

        if isinstance(item,Tree):        # This is True if item is a subclass of Tree

instead of

        if (type(item) == type(self)):   # This is False if item is a subclass of Tree

and change

data = self.data

to

data = self.data[:]

in getRight. When you say data = self.data then the variable name data points at the very same list that self.data points at. When you subsequently reverse data, you reverse self.data as well. To reverse only data, you must copy the list. self.data[:] uses slicing notation to return a copy of the list. Note that the elements of self.data can be Trees, and self.data and self.data[:] can contain identical elements. I don't think your code requires these elements to be copied, but you'll need to recursively copy self.data if that is the case.

def getRight(self):
    data = self.data[:]
    data.reverse()
    return data
unutbu
Thank you, that worked.
Mikk
Thank you for your note conserning copying lists. This was probably going to be my next problem.
Mikk
+2  A: 

When you define attributes in the following way:

class Tree:
    root = None
    data = []

..that empty list object is created as Python defines the class, not when you create a new instance. It is a class attribute, not an instance attribute. Meaning, Tree.root is the same object in all instances:

class Tree:
    root = None
    data = []

t1 = Tree()
t2 = Tree()

print id(t1.data) == id(t2.data) # is True, they are the same object

To get the behaviour you expect, move the creation of the empty list to the __init__ function, which is only called when you create a new instance, and only alters that instance (as it assigns to self):

class Tree:
    def __init__(self):
        self.root = None
        self.data = []

t1 = Tree()
t2 = Tree()

print id(t1.data) == id(t2.data) # False, they are different objects

This question explains why such behaviour can be useful

dbr