2010-05-20 5 views
4

Я новичок в Python и это материал OOP и не могу заставить его работать. Вот мой код:Python OOP и списки

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()); 

Похоже, что дерево2 и дерево разделяют список «данных»?

На данный момент я бы хотел, чтобы вывести что-то вроде [[20,44], 10, 4], но когда я

tree.appendLeft(tree2) 

я RuntimeError: maximum recursion depth exceeded, и, когда я даже не буду appendLeft(tree2) он выводит [10, 20, 44, 4] (!!!). Что мне здесь не хватает? Я использую Portable Python 3.0.1.

Спасибо

+0

Я был смущен тем же поведением, и спросил [этот вопрос, «почему приписывать справочник ces действуют как это с наследованием Python "] (http://stackoverflow.com/questions/206734/why-do-attribute-references-act-like-this-with-python-inheritance), которые могут представлять интерес – dbr

ответ

9

Проблема заключается в том, что вы объявили data в качестве переменной класса, так что все экземпляры класса разделяют тот же список. Вместо этого поставьте self.data = [] в свой __init__.

Кроме того, избавиться от всех этих точек с запятой. Они не нужны и загромождают ваш код.

+3

+ 1 для ответа плюс точка с запятой Замечание – catchmeifyoutry

+0

Спасибо, не ожидал, что объявление их как переменной класса сделает их «глобальными». Наконец, я могу закончить домашнюю работу :). – Mikk

+0

Написание точек с запятой в конце строки - это просто привычная форма java и PHP, удалит их :) – Mikk

4

Переместить корень и данные в определение __init__. Как бы то ни было, вы определили их как атрибуты класса. Это делает их доступными для всех экземпляров класса Tree. Когда вы создаете экземпляр двух деревьев (tree и tree2), они оба используют один и тот же список, к которому обращаются self.data. Чтобы каждый экземпляр имел свой собственный атрибут экземпляра, вы должны переместить объявление в функцию __init__.

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

Кроме того, использование

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

вместо

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

и изменить

data = self.data 

к

data = self.data[:] 

в getRight. Когда вы говорите data = self.data, тогда имя переменной data указывает на тот же список, что и self.data баллов. При последующем обратном data вы также можете изменить self.data. Чтобы изменить только data, вы должны скопировать список. self.data[:] использует режущую нотацию, чтобы вернуть копию списка. Обратите внимание, что элементы self.data могут быть Tree s, а self.data и self.data[:] могут содержать одинаковые элементы. Я не думаю, что ваш код требует, чтобы эти элементы были скопированы, но вам придется рекурсивно копировать self.data, если это так.

def getRight(self): 
    data = self.data[:] 
    data.reverse() 
    return data 
+0

Спасибо, что сработало. – Mikk

+0

Благодарим вас за то, что вы записали свои копии. Вероятно, это будет моей следующей проблемой. – Mikk

3

При определении атрибутов следующим образом:

class Tree: 
    root = None 
    data = [] 

..это создаются в Python пустого объекта списка определяет класс, а не при создании нового экземпляра. Это атрибут класса, а не атрибут экземпляра.Значение, Tree.root тот же объект во всех случаях:

class Tree: 
    root = None 
    data = [] 

t1 = Tree() 
t2 = Tree() 

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

Чтобы получить поведение, которое вы ожидаете, переместить создание пустого списка функции __init__, которая называется только тогда, когда вы создаете новый экземпляр, и только изменяет этот экземпляр (как он присваивает 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 объясняет, почему такое поведение может быть полезным