2011-03-25 77 views
3

我已经为dict内置类编写了一个小包装,该类可在第一次访问相应键时立即从cPickle d文件中加载词典的条目(值) 。当字典被销毁时,所有加载的条目被写回磁盘。Python:测试词典(词典)条目是否已被修改

现在,如果我可以检查是否有任何值已被更改并只写出实际上已经存在的值,那将很方便。 因此,我的问题是:字典是否知道值是否已被更改?还是有一个聪明的方法来透明地实现这一点?

为了完整起见,我附上我使用的代码。它被称为存储文件的路径(键被用作文件名)以及存在文件的键的列表。

import cPickle 

class DictDB(dict): 

    def __init__(self, path, folders): 
    self.picklepath  = path # path to files on disk 
    self.folders  = folders # available folders 
    self.loaded_folders = {} 

    def has_key(self, key): 
    return key in self.folders 

    def get(self, key): 
    if not key in self.loaded_folders.keys(): 
     if not key in self.folders: 
     raise KeyError("Folder "+key+" not available") 
     # load from disk 
     self.loaded_folders[key] = cPickle.load(file(self.picklepath + key + ".cpickle2")) 
    return self.loaded_folders[key] 

    def __getitem__(self, key): 
    return self.get(key) 

    def close(self): 
    for folder in self.loaded_folders.keys(): 
     # write back 
     cPickle.dump(self.loaded_folders[folder], file(picklepath + folder + '.cpickle2', 'w'), 2) 

    def __del__(self): 
    self.close() 
+0

值是否可变? – 2011-03-25 10:33:31

+0

是的,他们几乎总是'dict's本身。 – fuenfundachtzig 2011-03-25 10:39:49

回答

1

我可能会用一种发布 - 订阅模式来处理它,其中包含的字典订阅每个子字典(或其他值)。然后当它们中的一个被编辑时,它会通知包含它的任何字典。

如果您不希望它们全部处理接线,并且愿意允许包含的字典仅检查访问上的更改或以设定的时间间隔进行检查,则可以让每个包含的对象跟踪一个version号码。然后,当包含的字典准备就绪时,它仅检查该版本号是否已更改。

最后的可能性是有一种方法可靠地计算所包含对象的散列值。这可以让你编写一个外部函数,并且不再需要这些对象来跟踪他们自己的版本,但是它有自己的复杂性,因为你需要在所有这些版本上重载__hash__或者编写另一种形式的hash()函数识别对象并从中获取某种智能散列值

+0

我最终得到了类似于你的第一个建议;最后,这意味着我还必须包装所有存储在父字典中的'list'和'dict'对象,以便在更改时通知父字典。 – fuenfundachtzig 2011-07-19 10:00:53

1

我认为,你可以覆盖__setitem__()方法跟踪的值的变化,存储在列表中的变化值,并使用该列表中选择正确的价值观写出来。

+0

看到Janne的评论我注意到我应该提到这些值本身不会被替换,但会被修改,这意味着'DictDB .__ setitem()__'不会被调用(我猜)。 - 但最后你是对的,我需要更进一步,并使用另一个字典类的包装作为值。 – fuenfundachtzig 2011-03-25 10:42:46

+0

问题的确在于当__setitem()__'被存储为父'dict'中的值时,像'list'或'dict'这样的对象被更改时,不会调用__setitem()__。 – fuenfundachtzig 2011-07-19 09:59:38

0

您可以存储每个值的两个副本:原始状态和可能的修改状态。然后简单地将它们与!=进行比较以选择要写出的内容。

+0

这当然是可能的,但由于值是大对象,我宁愿不保留它们的两个副本。 (事实上​​,它们如此之大,使得我可以单独加载它们,并且只能根据请求加载它们,否则我只能“腌制”整个“字典”。) – fuenfundachtzig 2011-03-25 16:10:19

0

内存允许时,您可以保留从磁盘读取的原始值的副本,并在close()方法中比较当前值与原始值,只写出更改。

该方法给了字典中更多的自由,因为元素不需要跟踪对它们所做的更改。

+0

与Janne相同的想法,来自我的相同评论:) – fuenfundachtzig 2011-03-25 16:10:39