2016-03-28 5 views
0

У меня возникли проблемы с определением класса, которое я написал, что вызывает объект, который вызывает метод класса, который нужно изменить. Такое поведение изменения объекта нежелательно. Я хотел бы, чтобы метод класса мог добавлять два объекта вместе и выплевывать новый объект того же типа, т. Е. A = b + cМетод класса Python-2.7, вызывающий объекты

Мое определение класса для добавления создает новый экземпляр типа класса для хранения результаты комбинации двух объектов. Проблема в том, что после завершения вызывающий объект изменяется так же, как сумма двух объектов.

Ниже приведен минимальный рабочий пример нежелательного поведения. Код создает два экземпляра класса и инициализирует их некоторыми случайными данными. Каждый объект содержит два списка равных длин и целое число, которое содержит длины списков. Затем основной код печатает содержимое каждого объекта, вызывает метод добавления и сохраняет данные в новом объекте и, наконец, печатает содержимое исходных объектов.

У меня возникла проблема с изменяемыми параметрами по умолчанию, когда я создавал инициализацию для класса. Я думаю, что это еще один случай, когда я не понимаю, когда изменяет поведение в коде Python и как его предотвратить.

class myClass: 

     def __init__(self,list_a=None,list_b=None,list_count=0): 
       self.list_a=[] if list_b is None else list_a 
       self.list_b=[] if list_b is None else list_b 
       self.list_count = list_count 

     def add_data(self,ElementA,ElementB): 
       self.list_a.append(ElementA) 
       self.list_b.append(ElementB) 
       self.list_count = self.list_count + 1 

     def print_data(self): 
       print("Number of elements in this object is: %d"%self.list_count) 
       print("List A contents\n%s"%self.list_a) 
       print("List B contents\n%s\n"%self.list_b) 

     def addTogether(self,other): 
       test_data = myClass(self.list_a,self.list_b,self.list_count) 

       for i in range(0,other.list_count): 
         test_data.add_data(other.list_a[i],other.list_b[i]) 

       return(myClass(test_data.list_a,test_data.list_b,test_data.list_count)) 

import random 

object_array = [myClass() for i in range(2)] 
#Loop over object array and fill each object with some data 
for i in range(0,2): 

     NumData = int(10*random.random()) 
     for m in range(0,NumData): 
       #Generate some junk data to insert into the list of this object 
       ListAData = int(10*random.random()) 
       ListBData = int(10*random.random()) 

       object_array[i].check_data() 
       object_array[i].add_data(ListAData,ListBData) 
       object_array[i].check_data() 

object_array[0].print_data() 
object_array[1].print_data() 

new_data = object_array[0].addTogether(object_array[1]) 
new_data.print_data() 

object_array[0].print_data() 
object_array[1].print_data() 

Выход из кода:

Number of elements in this object is: 2 
List A contents 
[6, 5] 
List B contents 
[8, 7] 

Number of elements in this object is: 2 
List A contents 
[7, 6] 
List B contents 
[5, 3] 

Number of elements in this object is: 4 
List A contents 
[6, 5, 7, 6] 
List B contents 
[8, 7, 5, 3] 

Number of elements in this object is: 2 
List A contents 
[6, 5, 7, 6] 
List B contents 
[8, 7, 5, 3] 

Number of elements in this object is: 2 
List A contents 
[7, 6] 
List B contents 
[5, 3] 
+2

Это действительно трудно читать. Используйте правильные соглашения об именах PEP8; экземпляры и атрибуты должны быть lower_case_with_underscore: 'list_a',' object_array', 'list_a_data' и т. д. –

+0

Можете ли вы дать ясный пример ввода и вывода? –

+0

Я добавил образец вывода @ReutSharabani. В коде нет ввода. – wandadars

ответ

0

Чтобы "защитить" входящие списки, которые только сгруппированный-вместе ссылки на объекты, просто неглубоко скопировать их на строительство:

self.ListA=[] if ListA is None else ListA[:] 
self.ListB=[] if ListB is None else ListB[:] 

Обратите внимание: mylist[:] дублирует список (а не внутренние объекты, хотя это мелкая копия) и защищает любые внешние ссылки на существующий список источников.

В настоящее время вы изменяете списки, которые вы даете при строительстве.

Пример:

List A contents 
[1, 7, 6, 9, 8, 8, 5, 0] 
List B contents 
[8, 9, 3, 5, 1, 3, 1, 8] 

Number of elements in this object is: 8 
List A contents 
[7, 3, 1, 3, 9, 2, 8, 0] 
List B contents 
[8, 6, 6, 5, 0, 1, 8, 9] 

Number of elements in this object is: 16 
List A contents 
[1, 7, 6, 9, 8, 8, 5, 0, 7, 3, 1, 3, 9, 2, 8, 0] 
List B contents 
[8, 9, 3, 5, 1, 3, 1, 8, 8, 6, 6, 5, 0, 1, 8, 9] 

Number of elements in this object is: 8 
List A contents 
[1, 7, 6, 9, 8, 8, 5, 0] 
List B contents 
[8, 9, 3, 5, 1, 3, 1, 8] 

Number of elements in this object is: 8 
List A contents 
[7, 3, 1, 3, 9, 2, 8, 0] 
List B contents 
[8, 6, 6, 5, 0, 1, 8, 9] 
+0

Прошу прощения за эту путаницу с '[list]' и 'list [:]', верно ли это в редакторе :-) –

1

Проблема заключается в том, что вы используете списки от объекта А без их копирования, так что, когда они изменяются оригиналы изменяются слишком. Есть много способов исправить это, что можно найти here. Я предпочитаю использовать list(). Это позволит сделать ваш метод addTogether выглядеть следующим образом:

def addTogether(self,other): 
     TestData = myClass(list(self.ListA),list(self.ListB),self.ListCount) 

     for i in range(0,other.ListCount): 
       TestData.add_data(other.ListA[i],other.ListB[i]) 

     return(TestData) 

Вы, кажется, сохранение двух параллельных массивов. Как правило, это не очень хорошая идея. Я предлагаю подумать о создании объекта, который содержит свойства для данных, хранящихся в списке A и в списке B. Затем вы можете создать список из них. Слияние списков становится тривиальным.

0

Вы правы, это тот же список. Сделайте копию его, используя [:] и работает для меня.

def addTogether(self,other): 
      TestData = myClass(self.ListA[:],self.ListB[:],self.ListCount) 

      for i in range(0,other.ListCount): 
        TestData.add_data(other.ListA[i],other.ListB[i]) 

      return TestData 

 Смежные вопросы

  • Нет связанных вопросов^_^