2014-01-17 3 views
1

Я имею дело с некоторыми классами с использованием модуля pygraph, и когда я использую метод add_node(), он всегда выводит «узел xxx уже в графе». Поэтому я стараюсь использовать DeepCopy(), чтобы создать новый экземпляр и есть некоторые проблемы с ним:Создайте новый объект obj с функцией deepcopy, но с новой переменной obj с старым obj

class test: 
    _storage = [] 
    def add_item(self,item): 
     self._storage.append(item) 

    def pop_item(self,item): 
     return self._storage.pop() 

    def __repr__(self): 
     return '%s' %self._storage[:] 

if __name__ == '__main__': 
    a1 = test() 
    a1.add_item(3) 
    a1.add_item(4) 
    from copy import copy,deepcopy 
    a2 = copy(a1) 
    a3 = deepcopy(a2) 

он показывает:

In[28]: a1 
Out[28]: [3, 4] 

In[29]: a2 
Out[29]: [3, 4] 

In[30]: a3 
Out[30]: [3, 4] 

но если я добавить новый элемент в список a2, a3 изменения тоже

In[31]: a1.add_item(440) 

In[32]: a2 
Out[32]: [3, 4, 440] 

In[33]: a3 
Out[33]: [3, 4, 440] 

Так как я могу просто скопировать какой-то экземпляр, а его переменные не зависят от переменных в старом экземпляре?

ответ

3

_storage - переменная класса. deepcopy не будет создавать новую копию всего класса, поэтому копии по-прежнему будут иметь одни и те же переменные класса. То, что вы хотите, это переменная экземпляра:

def __init__(self): 
    self._storage = [] 
+0

Спасибо, но a2, a3 все еще меняется с помощью a1, поэтому они по-прежнему используют _stora ge и я не знаю, как с этим бороться –

+1

@ user3001921: Этого не должно быть. Объект 'deepcopy'd должен иметь свой собственный' _storage'. Покажите нам новую версию вашего кода. Вы правильно написали '__init__'? Удалили ли вы класс __storage? Вы сделали '__init__' метод' test'? – user2357112

+0

это правильный ответ .... как показано в моем ответе ... есть другие способы сделать это, но это ясный способ сделать это в вашем случае –

1
class test: 
    storage = [] 
    def add_item(self,item): 
     self.storage.append(item)  
    def pop_item(self,item): 
     return self.storage.pop()  
    def __repr__(self): 
     return '%s' %self.storage[:] 
    def __copy__(self): 
     print "COPY!!!" #define explicit copy behaviour 
     s = self.__class__() 
     s.storage = self.storage[:] # make a copy of the list rather than a pointer to same 
     return s 

from copy import copy 
a = test() 
a.add_item(3) 
a.add_item(4) 
b = copy(a) #this will call the __copy__ method of the class 
b.add_item(244) 
a.add_item(5) 
print a,b 

в качестве альтернативы вы можете просто создать метод copy на классе и вызвать b = a.copy()

или вы можете использовать раствор из user2357112, который действительно работает (и намного больше pythonic, если вам действительно не нужно определять явное поведение)

>>> class test: 
... def __init__(self): 
...  self.storage = [] 
... def add_item(self,item): 
...  self.storage.append(item) 
... def pop_item(self,item): 
...  return self.storage.pop() 
... def __repr__(self): 
...  return '%s' %self.storage[:] 
... 
>>> a = test() 
>>> a.add_item(1) 
>>> b = deepcopy(a) 
>>> b.add_item(4) 
>>> b 
[1, 4] 
>>> a 
[1] 
Смежные вопросы