2011-03-25 2 views
3

J'ai écrit un petit wrapper pour la classe intégrée dict qui charge les entrées (valeurs) d'un dictionnaire depuis cPickle d fichiers dès que la clé correspondante est accédée pour la première fois . Lorsque le dictionnaire est détruit, toutes les entrées chargées sont réécrites sur le disque.Python: Test si l'entrée du dictionnaire (dict) a été modifiée

Maintenant, il serait pratique que je vérifie si l'une des valeurs a été modifiée et n'écris que celles qui l'ont été. Ma question est donc la suivante: un dictionnaire sait-il si une valeur a été modifiée? Ou y a-t-il un moyen intelligent d'implémenter cela de manière transparente?

Pour être complet, je joins le code que j'utilise. Il est appelé avec le chemin où les fichiers sont stockés (les clés sont utilisées comme noms de fichiers) et avec une liste de clés pour lesquelles des fichiers existent.

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

Les valeurs sont-elles mutables? –

+0

Oui, ils sont presque toujours eux-mêmes. – fuenfundachtzig

Répondre

1

Je pourrais l'approcher avec une sorte de modèle de publication-abonnement, où le dictionnaire contenant souscrit à chacun des sous-dictionnaires (ou d'autres valeurs). Puis, quand l'un d'entre eux est édité, il avertit tous les dictionnaires qui le contiennent. Si vous ne voulez pas qu'ils traitent tous du câblage pour cela et acceptent que le dictionnaire contenant ne vérifie que les changements d'accès ou à des intervalles définis, vous pouvez faire en sorte que chaque objet contenu garde une trace d'un numéro version . Ensuite, lorsque le dictionnaire contenant est prêt, il vérifie simplement si ce numéro de version a changé.

Une dernière possibilité serait d'avoir un moyen de calculer de façon fiable des valeurs de hachage pour les objets contenus en place. Cela vous permettrait d'écrire une fonction externe et de supprimer le besoin pour les objets de suivre leurs propres versions, mais a ses propres complexités puisque vous devrez soit surcharger __hash__ sur chacun d'eux ou écrire une autre forme de la fonction hash() qui peut identifier l'objet et en tirer une sorte de valeur hachée intelligente

+0

Je me suis retrouvé avec quelque chose comme votre première suggestion; à la fin, cela signifiait que je devais également emballer tous les objets 'list' et' dict' que je stocke dans le dictionnaire parent afin qu'ils notifient le dictionnaire parent lors d'un changement. – fuenfundachtzig

1

Je pense que vous pouvez remplacer la méthode __setitem__() de garder une trace des changements des valeurs, stockant les valeurs modifiées dans une liste, et utiliser cette liste pour choisir les valeurs correctes pour écrire.

+0

En voyant le commentaire de Janne J'ai remarqué que j'aurais dû mentionner que les valeurs elles-mêmes ne seront pas remplacées, mais modifiées, ce qui signifie que 'DictDB .__ setitem() __' ne serait pas appelé (je suppose). - Mais à la fin tu as raison de devoir aller plus loin et utiliser une autre enveloppe de la classe dict comme valeurs. – fuenfundachtzig

+0

Le problème est en effet que '__setitem() __' n'est pas appelé quand un objet comme 'list' ou' dict' qui est stocké comme valeur dans le parent 'dict' est changé. – fuenfundachtzig

0

Vous pouvez stocker deux copies de chaque valeur: état d'origine et état éventuellement modifié. Ensuite, il suffit de les comparer avec != pour choisir lequel écrire.

+0

C'est certainement possible, mais comme les valeurs sont de gros objets, je préfère ne pas en garder deux copies. (Le fait qu'ils soient si grands me fait les charger chacun séparément et seulement sur demande, sinon je pourrais simplement «décaper» toute la «dict». – fuenfundachtzig

0

Si la mémoire le permet, vous pouvez conserver une copie des valeurs d'origine lues à partir du disque et, dans la méthode close(), comparer les valeurs actuelles aux valeurs d'origine, en n'écrivant que les modifications.

Cette méthode donne plus de liberté dans ce qui peut être mis dans le dictionnaire, puisque les éléments n'ont pas besoin de garder trace des changements qui leur sont apportés.

+0

Même idée que Janne, même commentaire de moi :) – fuenfundachtzig

Questions connexes