包装python dict

时间:2017-11-11 09:39:59

标签: python dictionary inheritance

我想在python3中编写一个dict子类,它包含一些dict方法并返回同一类的实例而不是__getitem__上的dict,如果请求的值恰好是一个dict。否则,我想要的行为与dict的行为完全相同。这就是我想出的:

class WrappedDict(dict):
    def __init__(self, stuff, *args, **kwargs):
        super(WrappedDict, self).__init__(*args, **kwargs)
        self.stuff = stuff

    def update_stuff(self):
        pass  # Do things with stuff

    def update(self, *args, **kwargs):
        self.update_stuff(*args, **kwargs)
        super(WrappedDict, self).update(*args, **kwargs)

    def __getitem__(self, item):
        obj = super(WrappedDict, self).__getitem__(item)
        if isinstance(obj, dict):
            return WrappedDict(self.stuff + str(item), obj)
        else:
            return obj

然而,这与dict不同,因为它不返回对dict值的引用,而是从该dict创建的新对象。说明我的意思:

d1 = {'a': 1, 'b': 2, 'c': {'d': 4}}
d1.update(a=10)
d2 = d1['c']
d2.update(d=40)
print(d1)

会给:

{'a': 10, 'b': 2, 'c': {'d': 40}}

但对WrappedDict执行相同的操作:

wd1 = WrappedDict("stuff", {'a': 1, 'b': 2, 'c': {'d': 4}})
wd1.update(a=10)
wd2 = wd1['c']
wd2.update(d=40)
print(wd1)

给出:

{'a': 10, 'b': 2, 'c': {'d': 4}}

内部字典中的注释4而不是预期的40.有没有办法在没有太多黑魔法的情况下复制以前的行为?

1 个答案:

答案 0 :(得分:1)

使用WrappedDict

将新创建的__setitem__设置回您的对象
def __getitem__(self, item):
    obj = super(WrappedDict, self).__getitem__(item)
    if isinstance(obj, dict):
        wrapped = WrappedDict(self.stuff + str(item), obj)
        super(WrappedDict, self).__setitem__(item, wrapped)
        return wrapped
    else:
        return obj

完整代码:

class WrappedDict(dict):
    def __init__(self, stuff, *args, **kwargs):
        super(WrappedDict, self).__init__(*args, **kwargs)
        self.stuff = stuff

    def update_stuff(self, *args, **kwargs):
        pass  # Do things with stuff

    def update(self, *args, **kwargs):
        self.update_stuff(*args, **kwargs)
        super(WrappedDict, self).update(*args, **kwargs)

    def __getitem__(self, item):
        obj = super(WrappedDict, self).__getitem__(item)
        if isinstance(obj, dict):
            wrapped = WrappedDict(self.stuff + str(item), obj)
            super(WrappedDict, self).__setitem__(item, wrapped)
            return wrapped
        else:
            return obj

d1 = {'a': 1, 'b': 2, 'c': {'d': 4}}
d1.update(a=10)
d2 = d1['c']
d2.update(d=40)
print(d1)

wd1 = WrappedDict("stuff", {'a': 1, 'b': 2, 'c': {'d': 4}})
wd1.update(a=10)
wd2 = wd1['c']
wd2.update(d=40)
print(wd1)

输出:

{'a': 10, 'b': 2, 'c': {'d': 40}}
{'a': 10, 'b': 2, 'c': {'d': 40}}