深度复制用户定义的python字典

时间:2016-05-03 22:00:46

标签: python dictionary deep-copy

我有一个用户定义的字典(子类化python的内置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

我尝试按照建议的here覆盖deepcopy方法:

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} 
{}

任何想法如何解决这个问题?

2 个答案:

答案 0 :(得分:2)

您的deepcopy实施无效,因为dict的值未存储在__dict__中。 dict是一个特殊的类。您可以使用dict的深层复制来调用__init__

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]}

答案 1 :(得分:1)

这样的事情应该无需更改深度复制即可。

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

这会将x1投射到list深层复制,然后在分配给customList之前将其设为x2