2014-09-22 4 views
4

У меня есть подкласс dict, который добавляет новые методы и функции. Главное, что я хотел поддержать, - это рекурсивное обновление, которое работает путем обновления каждого вложенного dict по одному в отличие от метода dict.update.Поддерживает операцию глубокой копии в пользовательском классе?

Я использую функцию copy.deepcopy так же, как и любой другой объект, проблема заключается в том, что она не работает, когда я добавил доступ атрибута к этому классу:

__getattr__ = dict.__getitem__ 
__setattr__ = dict.__setitem__ 
__delattr__ = dict.__delitem__ 

Теперь я получаю эту ошибку:

KeyError: '__deepcopy__' 

copy.deepcopy функция пытается использовать __deepcopy__ метод этого объекта:

copier = getattr(x, "__deepcopy__", None) 

Почему после добавления __getattr__ это произошло? есть ли способ исправить это, не применяя метод __deepcopy__?


Я никогда не использовал метод __deepcopy__ поэтому я попытался добавить один, и это то, что у меня есть:

def __deepcopy__(self, memo): 
    # create a new instance of this object 
    new_object = type(self)() 

    # iterate over the items of this object and copy each one 
    for key, value in self.iteritems(): 
     new_object[key] = copy.deepcopy(value, memo) 

    return new_object 

Это правильный способ реализации __deepcopy__?

+0

Где находится остальное определение класса? Вы протестировали реализацию во второй половине своего вопроса? – jonrsharpe

ответ

2

Здесь не нужно вводить __deepcopy__.

Проблема заключается в том, что ваш __getattr__ всегда вызывает __getitem__, что поднимет KeyError на несуществующий атрибут. Но ожидается, что __getattr__ поднимет AttributeError.

Реализация getattr улавливает AttributeError, но не KeyError, и поэтому исключение не обрабатывается.

Вы должны изменить __getattr__, чтобы правильно поднять AttributeError в этом случае.

+0

Да. Это то, что я набирал. , , – mgilson

1

Для того, чтобы не повторять interjay, который, кажется, ninja'd всех нас, это хороший способ осуществить то, что вы хотите относительно безопасно:

class AttributeDict(dict): 
    def __init__(self): 
     self.__dict__ = self 

ad = AttributeDict() 
ad["a"] = 1 
ad.a 
#>>> 1 

import copy 
copy.deepcopy(ad) 
#>>> {'a': 1} 

Как классы просто красивые словари, это на самом деле один из самых быстрых способов сделать это на CPython. Поскольку он не перегружает __getattr__, это стандартное поведение, которое вы ожидаете от ошибок.

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