仅存储更改的Python字典

Ase*_*cus 5 python dictionary nested

我使用Inspyred库编写了一个用于设计优化的代码及其遗传算法的实现.本质上,优化过程在单个数据结构上创建了大量变体,在我的例子中,这是一个嵌套字典.

为了减少进程中使用的内存量,我一直在尝试创建某种差异字典类型,它只存储与基本字典不同的项目.其原因在于,在典型情况下,数据结构中95%的数据不会在任何变体中被修改,但数据结构的任何部分都可以包含变体.因此,出于灵活性的原因,我希望数据类型的行为或多或少像字典,但只存储更改.

这是我试图创建这个的结果:

#!/usr/bin/python

import unittest
import copy

global_base={}

class DifferentialDict(object):
    """
    dictionary with differential storage of changes
    all DifferentialDict objects have the same base dictionary
    """

    def __init__(self,base=None):
        global global_base

        self.changes={}

        if not base==None:
            self.set_base(base)

    def set_base(self,base):
        global global_base
        global_base=copy.deepcopy(base)

    def __copy__(self):
        return self

    def __deepcopy__(self):
        new=DifferentialDict()
        new.changes=copy.deepcopy(self.changes)
        return new

    def get(self):
        global global_base
        outdict=copy.deepcopy(global_base)
        for key in self.changes:
            outdict[key]=self.changes[key]
        return outdict

    def __setitem__(self,key,value):
        self.changes[key]=value

    def __getitem__(self,key):
        global global_base
        if key in self.changes:
            return self.changes[key]
        else:
            return global_base[key]

class TestDifferentialDict(unittest.TestCase):
    def test1(self):
        ldict={'a':{1:2,3:4},'b':{'c':[1,2,3],'d':'abc'}}
        ddict=DifferentialDict(base=ldict)

        self.assertEqual(ddict['a'],{1:2,3:4})
        ddict['a']=5
        self.assertEqual(ddict['a'],5)

    def test2(self):
        ldict={'a':{1:2,3:4},'b':{'c':[1,2,3],'d':'abc'}}
        ddict1=DifferentialDict(base=ldict)
        ddict2=DifferentialDict(base=ldict)

        ddict1['a'][3]=5
        ddict2['a'][3]=7
        self.assertEqual(ddict1['a'][3],5)
        self.assertEqual(ddict2['a'][3],7)

    def test3(self):
        ldict={'a':{1:2,3:4},'b':{'c':[1,2,3],'d':'abc'}}
        ddict1=DifferentialDict(base=ldict)
        ddict2=ddict1.__deepcopy__()

        ddict1['a'][3]=5
        ddict2['a'][3]=7
        self.assertEqual(ddict1['a'][3],5)
        self.assertEqual(ddict2['a'][3],7)



if __name__ == "__main__":
    unittest.main()
Run Code Online (Sandbox Code Playgroud)

它适用于简单的字典,但是当新字典嵌套在主字典中时会出现故障.我知道这是因为这些二级字典是真正的Python字典而不是我的DifferentialDict的实例化,导致覆盖global_base中的条目而不是self.changes中的更改.但是,它们必须是因为所有DifferentialDict实例共享相同的基本字典.我可以为每个DifferentialDict实例添加一个"入门级"键,但我的感觉是有一个更优雅的解决方案,这让我望而却步.

我真的很感激有关如何在嵌套时使我的差异字典工作的任何建议.提前致谢!

Geo*_*lly 3

我现在没有时间尝试这个(也许稍后),但这里有两个观察结果:

综合指数

如果您使用元组作为索引,例如像这样,dict[(5,3,2)]您就不会遇到此问题。如果你的基本字典或差分字典都以此为基础,你就可以避免这个问题。

也许您甚至可以编写一些重写的​​类dict[a][b][c]dict[(a,b,c)]使此内部更改透明。

全球基地

我不明白你为什么使用全球基地。从我的角度来看,这会使代码变得更加复杂,而无需添加任何内容。为什么不直接将基础存储为:

def MyDict(collections.abc.MutableSequence):
    def __init__(self, base):
        self._base = base

my_global_base = dict()
d = MyDict(my_global_base)

d[2] = 'abc' # modifies self._base inside of the instance too, because it is the
             # same object
Run Code Online (Sandbox Code Playgroud)

如果要更改库的所有内容,只需使用 删除所有项目popitem(),然后使用 添加新项目即可update()。这样您的代码就更加灵活,并且不会因为全局变量而出现任何令人惊讶的行为。

抽象基类

当重新实现序列、字典等类时,使用 Python 提供的抽象基类可能会派上用场,它们会为您完成一些实现工作。