2016-05-03 4 views
0

У меня есть определенные пользователем словарь (суб-причислять питон встроенный Dict объект), который не позволяет модифицировать Dict непосредственно:Глубокое копирование определенный пользователем словарь питона

class customDict(dict): 
    """ 
    This dict does not allow the direct modification of 
    its entries(e.g., d['a'] = 5 or del d['a']) 
    """ 
    def __init__(self, *args, **kwargs): 
     self.update(*args, **kwargs) 

    def __setitem__(self,key,value): 
     raise Exception('You cannot directly modify this dictionary. Use set_[property_name] method instead') 

    def __delitem__(self,key): 
     raise Exception('You cannot directly modify this dictionary. Use set_[property_name] method instead') 

Моя проблема заключается в том, что я Я не могу глубоко скопировать этот словарь, используя copy.deepcopy. Вот пример:

d1 = customDict({'a':1,'b':2,'c':3}) 
print d1 
d2 = deepcopy(d1) 
print d2 

, где он бросает исключение я определил себя за SetItem:

Exception: You cannot directly modify this dictionary. Use set_[property_name] method instead 

Я попытался перезапись DeepCopy метод следующим образом, как предложил here:

def __deepcopy__(self, memo): 
    cls = self.__class__ 
    result = cls.__new__(cls) 
    memo[id(self)] = result 
    for k, v in self.__dict__.items(): 
     setattr(result, k, deepcopy(v, memo)) 
    return result 

Это не вызывает никаких ошибок, но возвращает пустой словарь:

d1 = customDict({'a':1,'b':2,'c':3}) 
print d1 
d2 = deepcopy(d1) 
print d2 

{'a': 1, 'c': 3, 'b': 2} 
{} 

Любые идеи, как исправить это?

+4

Наследование, вероятно, не является хорошим решением для этого. Если ваш список не делает ничего, что кортеж не делает, просто используйте кортеж. В противном случае используйте шаблон прокси-шаблона («имеет значение« нет »является«) » – wim

+2

Зачем вам нужно глубоко скопировать неизменный список? – Natecat

+0

Также хороший вопрос! :) – wim

ответ

1

Нечто подобное должно работать без изменения глубины.

x2 = customList(copy.deepcopy(list(x1))) 

Это будет отбрасывать x1 к list DeepCopy тогда сделать его customList перед назначением на x2.

+0

Это отличное предложение! Единственное, что я на самом деле глубоко копирую, это класс, в котором этот список служит переменной экземпляра. Итак, мне все еще приходится перезаписывать метод deeopcoopy. Тем не менее, я просто поставлю: return customList (deepcopy (list (self))) в определении глубины, и он отлично работал! – user3076813

+0

Вместо использования customList (deepcopy (list (self))) Я использую self .__ init __ (deepcopy (list (self))).Он работает нормально, но проблема в том, что я получаю «RuntimeError: максимальная глубина рекурсии», хотя я использую sys.setrecursionlimit (10000) – user3076813

+0

Почему вы вызываете '__init __()'? Я думаю, когда вы вызываете 'self .__ init __ (deepcopy (list (self)))' вы вызываете бесконечную рекурсию. –

2

Реализация не работает, потому что значения dict не хранятся в __dict__. dict - особый класс. Вы можете заставить его работать, вызывая __init__ с глубокой копией dict.

def __deepcopy__(self, memo): 
    def _deepcopy_dict(x, memo): 
     y = {} 
     memo[id(x)] = y 
     for key, value in x.iteritems(): 
      y[deepcopy(key, memo)] = deepcopy(value, memo) 
     return y 
    cls = self.__class__ 
    result = cls.__new__(cls) 
    result.__init__(_deepcopy_dict(self, memo)) 
    memo[id(self)] = result 
    for k, v in self.__dict__.items(): 
     setattr(result, k, deepcopy(v, memo)) 
    return result 

Эта программа

d1 = customDict({'a': 2,'b': [3, 4]}) 
d2 = deepcopy(d1) 
d2['b'].append(5) 

print d1 
print d2 

Выходы

{'a': 2, 'b': [3, 4]} 
{'a': 2, 'b': [3, 4, 5]} 
+0

Похоже, что 'memo' хранит ссылки на оригиналы, а не на копии. Должно ли это быть 'memo [id (self)] = self', на самом деле? Первый ответ на ссылку в вопросе также предлагает это. –

+0

Нет. См. Например https://github.com/numpy/numpy/blob/090bbdd8f3debe0b6a6c4aa542937edf250f9443/numpy/ma/core.py#L5852 – malbarbo

+0

Это не работает для словаря. Вот пример: d1 = customDict ({'a': 2, 'b': [3,4]}) d2 = deepcopy (d1) d2 ['b']. Append (5) print d1 print d2 {'a': 2, 'b': [3, 4, 5]} {'a': 2, 'b': [3, 4, 5]} print d2 – user3076813

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