2016-05-10 1 views
1
data = {'murtaza':('arnav', 'ohjun'), 
     'ohjun':('arnav', 'murtaza'), 
     'arnav':('ohjun', 'murtaza')} 

class node: 
    predecessors=[] 
    nexts=[] 
    student='' 
    def __init__(self, student='', predecessors=[]): 
     self.student=student 
     self.predecessors=predecessors 
    def grow(self, max=6, depth=0): 
     if not self.student in self.predecessors: 
      self.predecessors.append(self.student) 
      for pref in data[self.student]: 
       next=node(pref, self.predecessors) 
       print(depth, self.predecessors, self.student, pref) 
       next.grow(max, depth=depth+1) 
       self.nexts.append(next) 
     else: 
      return 

Итак, вот мои данные и определение класса для узла. То, что я ожидаю, когда я вызову метод grow() для объекта узла, выглядит следующим образом: он ищет имя студента в данных, а затем для каждого из имен, связанных с этим учеником (т.е. их предпочтения, следовательно, for pref in data[self.student]) создает новый узел добавляет его к ветвящимся узлам от текущего узла, а затем вызывает grow() на этом новом узле. Затем этот метод продолжит создание дерева, если студент не появится дважды в последовательности, следовательно, проверка if not self.student in self.predecessors.Дерево, похоже, неправильно построено в Python

Проблема заключается в том, что предшественники не запоминаются правильно в дереве. По какой-то причине узел брата внезапно получает всех предшественников своих детей. Вот вывод программы:

0 ['murtaza'] murtaza arnav 
1 ['murtaza', 'arnav'] arnav ohjun 
2 ['murtaza', 'arnav', 'ohjun'] ohjun arnav 
2 ['murtaza', 'arnav', 'ohjun'] ohjun murtaza #as expected up to here 
1 ['murtaza', 'arnav', 'ohjun'] arnav murtaza 
0 ['murtaza', 'arnav', 'ohjun'] murtaza ohjun 

Я бы ожидать, что читать:

0 ['murtaza'] murtaza arnav 
1 ['murtaza', 'arnav'] arnav ohjun 
2 ['murtaza', 'arnav', 'ohjun'] ohjun arnav 
2 ['murtaza', 'arnav', 'ohjun'] ohjun murtaza 
1 ['murtaza', 'arnav'] arnav murtaza 
0 ['murtaza'] murtaza ohjun 
1 ['murtaza', 'ohjun'] ohjun arnav 
2 ['murtaza', 'ohjun', 'arnav'] arnav ohjun 
2 ['murtaza', 'ohjun', 'arnav'] arnav murtaza 
1 ['murtaza', 'ohjun'] ohjun murtaza 

Могу ли я понять код я написал неправильно, или мое понимание алгоритма не так? Или моя реализация неверна? Я действительно думал, что понял, как сделать дерево, но это, похоже, не работает так, как мне кажется.

Edit: Я хотел бы добавить, что основной корпус выглядит следующим образом:

mort = node() 
mort.student='murtaza' 
mort.grow() 

ответ

2

Эта строка:

next=node(pref, self.predecessors) 

не делает копию self.predecessors, вместо этого он передает ссылку на именованный list объект. Аналогичным образом эта строка:

self.predecessors=predecessors 

не делает копию predecessors. Следовательно, все ваши объекты node работают в том же списке; когда один объект вызывает .append(), обновляется список всех объектов 'predecessor.

Решение состоит в том, чтобы заменить один из этих вызовов с copy.deepcopy(), например, так:

self.predecessors = copy.deepcopy(predecessors) 

В зависимости upong вашей точной структуры данных, вам может понадобиться copy.copy() вместо этого.

Кроме того, возможно, не связанный с вашим вопросом, ваше предоставление значения по умолчанию для predecessors в __init__() не будет работать так, как вы ожидаете. (См. here). Попробуйте это вместо:

def __init__(self, student='', predecessors=None): 
    self.student=student 
    if predecessors is None: 
     self.predecessors = [] 
    else: 
     self.predecessors=copy.deepcopy(predecessors) 
+0

Большое спасибо, результат точно так, как я ожидал сейчас. Не могу поверить, что я это забыл. Python должен иметь большую ясность, когда по умолчанию передается что-то, а иногда я забываю, что объекты передаются по ссылке, но я думаю, я привык к этому. – murtaza64

+0

Также эта ссылка была хорошей, прочитайте, спасибо. – murtaza64

+1

@ murtaza64 Существует вся ясность, которая может быть: что-то * НИКОГДА * не копируется. Ваша проблема - изменчивость объектов, переданных по ссылке. Существует очень простое правило для предотвращения, по крайней мере, некоторых из ваших проблем: никогда не объявляйте атрибуты уровня класса (предшественник, следующий). Это * NOT * java или C++, где работает этот вид синтаксиса – deets