En bref: quel est le moyen jeûné pour vérifier si une liste énorme en python a changé? longue. J'ai une liste énorme de dictionnaires représentant des données. Je lance un certain nombre d'analyses sur ces données, mais il y a quelques aspects méta-données qui sont requises par toutes les analyses, par exemple. le l'ensemble des sujets (chaque dict dans la liste a une clé de sujet, et parfois j'ai juste besoin d'une liste de tous les objets qui ont des données présentes dans l'ensemble de données.). Je voudrais donc mettre en œuvre ce qui suit: p> hashlib code> a besoin d'un tampon, et la construction d'une représentation de chaîne de cette liste est infaisable class Data:
def __init__(self, ...):
self.data = [{...}, {...}, ...] # long ass list of dicts
self.subjects = set()
self.hash = 0
def get_subjects(self):
# recalculate set of subjects only if necessary
if self.has_changed():
set(datum['subject'] for datum in self.data)
return self.subjects
def has_changed(self):
# calculate hash of self.data
hash = self.data.get_hash() # HOW TO DO THIS?
changed = self.hash == hash
self.hash = hash # reset last remembered hash
return changed
3 Réponses :
Vous pouvez facilement obtenir la représentation de chaîne d'un objet à l'aide de la bibliothèque de conserves au vinaigre, puis le transmettre à hashlib, comme vous avez dit:
import pickle
import hashlib
data = []
for i in xrange(100000):
data.append({i:i})
print hashlib.md5(pickle.dumps(data))
data[0] = {0:1}
print hashlib.md5(pickle.dumps(data))
Cela fonctionne bien, mais est assez lent. Le problème est que je ne sais pas toujours si une opération modifiera la liste (plus grand nombre des analyses que j'utilise ont été écrites par d'autres personnes, et changer tous est impossible). La fonction ne doit même pas être tout à fait précis, un rapide has_probably_changed code> va faire.
hashlib a besoin d'un tampon, et la construction d'une chaîne de caractères représentant que la liste est infaisable. p>
Une approche plus sophistiquée, il serait de travailler avec des éléments de données proxy au lieu de listes natives et des dictionnaires, ce qui pourrait signaler tout changement à leurs attributs. Pour le rendre plus flexible, vous pouvez même le code d'un rappel à utiliser dans le cas de modifications
Alors, en supposant suffit de traiter des listes et des dictionnaires sur votre structure de données -. Nous pouvons travailler avec des classes héritant de dict et liste avec un rappel automatique lorsque des données procédé de changement de l'objet est accessible la liste complète des méthodes est en http : //docs.python.org/reference/datamodel.html p>
# -*- coding: utf-8 -*-
# String for doctests and example:
"""
>>> a = NotifierList()
>>> flag.has_changed
False
>>> a.append(NotifierDict())
>>> flag.has_changed
True
>>> flag.clear()
>>> flag.has_changed
False
>>> a[0]["status"]="new"
>>> flag.has_changed
True
>>>
"""
changer_methods = set("__setitem__ __setslice__ __delitem__ update append extend add insert pop popitem remove setdefault __iadd__".split())
def callback_getter(obj):
def callback(name):
obj.has_changed = True
return callback
def proxy_decorator(func, callback):
def wrapper(*args, **kw):
callback(func.__name__)
return func(*args, **kw)
wrapper.__name__ = func.__name__
return wrapper
def proxy_class_factory(cls, obj):
new_dct = cls.__dict__.copy()
for key, value in new_dct.items():
if key in changer_methods:
new_dct[key] = proxy_decorator(value, callback_getter(obj))
return type("proxy_"+ cls.__name__, (cls,), new_dct)
class Flag(object):
def __init__(self):
self.clear()
def clear(self):
self.has_changed = False
flag = Flag()
NotifierList = proxy_class_factory(list, flag)
NotifierDict = proxy_class_factory(dict, flag)
Je chaleureusement deuxième cette approche. Si la détection des changements après le fait est trop cher (que votre description indique qui est certainement le cas), suivre simplement les changements qu'ils se produisent. La raison d'utiliser une empreinte de hachage comme Nkosinathi est à l'origine essayé si vous devez conserver plusieurs versions mises en cache et ont besoin d'une façon de les identifier de manière unique. Si tout ce que vous faites est la détection des changements, cette approche est beaucoup plus approprié.
Comment votre méthode
change_data code> ressembler? Aussiself.subjects code> peut être construit commeself.subjects = set (niveau de référence [ 'sujet'] pour référence dans self.data) code>.Je pense que vous pourriez avoir besoin de donner plus de détails. Avez-vous des deux versions anciennes et nouvelles? Pouvez-vous utiliser frozendicts? Est-ce que la matière de commande? Votre code crée les changements?
Pouvez-vous avoir juste un
has_changed code> variable d'instance vous définissez à chaque fois que vous changezdonnées code>? Dans le cas contraire, vous avez probablement besoin d'un objet proxy de déléguer tout saufhas_changed code> réeldonnées code>.Mis à part la question: rendre votre Hériter de la classe de données de « objet » ou vous obtiendrez des erreurs subtiles et difficiles à identifier lorsqu'ils ont besoin de plus de soutien de mécanismes Python OO (ce qui est exactement votre cas)
Plus précisément - idetifying si un Liste i> a changé est relativement facile - il change si l'identifiant d'un objet qu'il contient changent. Vous semblez avoir besoin d'être informé de tout changement dans tous les éléments imbriqués mutables sur votre liste, est-ce pas?