2012-09-25 4 views
0

Je possède ce (Py2.7.2):Révéler les valeurs dict via les propriétés

class MyClass(object): 
    def __init__(self, dict_values): 
     self.values = dict_values 
     self.changed_values = {} #this should track changes done to the values{} 
     .... 

Je peux l'utiliser comme ceci:

var = MyClass() 
var.values['age'] = 21 
var.changed_values['age'] = 21 

Mais je veux l'utiliser comme ceci:

var.age = 21 
print var.changed_values #prints {'age':21} 

Je suppose que je peux utiliser des propriétés pour le faire, mais comment?

MISE À JOUR:

Je ne sais pas le contenu de dict au moment de la conception. Il sera connu à l'exécution seulement. Et il ne sera probablement pas vide

+1

À quoi sert 'changed_values'? Quand cela diffère-t-il des 'valeurs'? Qu'est-ce que cela vous permet? – delnan

+0

Simple - Je veux voir ce qui a été changé exactement. Oui, il peut être remplacé par une liste de clés, mais ce n'est pas le but de la question. – AlexVhr

+0

Je veux dire, comment est-ce que le fait de regarder les clés de 'valeurs' ne fonctionne pas pour vous? Est-ce que les items sont toujours retirés de 'changed_values' et les valeurs de' changed_values' changent-elles les valeurs actuelles dans 'values'? – delnan

Répondre

1

Vous pouvez créer une classe qui hérite d'un dict et passer outre les fonctions nécessaires

class D(dict): 
    def __init__(self): 
     self.changed_values = {} 
     self.__initialized = True 

    def __setitem__(self, key, value): 
     self.changed_values[key] = value 
     super(D, self).__setitem__(key, value) 

    def __getattr__(self, item): 
     """Maps values to attributes. 
     Only called if there *isn't* an attribute with this name 
     """ 
     try: 
      return self.__getitem__(item) 
     except KeyError: 
      raise AttributeError(item) 

    def __setattr__(self, item, value): 
     """Maps attributes to values. 
     Only if we are initialised 
     """ 
     if not self.__dict__.has_key('_D__initialized'): # this test allows attributes to be set in the __init__ method 
      return dict.__setattr__(self, item, value) 
     elif self.__dict__.has_key(item):  # any normal attributes are handled normally 
      dict.__setattr__(self, item, value) 
     else: 
      self.__setitem__(item, value) 

a = D() 
a['hi'] = 'hello' 
print a.hi 
print a.changed_values 

a.hi = 'wow' 
print a.hi 
print a.changed_values 

a.test = 'test1' 
print a.test 
print a.changed_values 

sortie

>>hello 
>>{'hi': 'hello'} 
>>wow 
>>{'hi': 'wow'} 
>>test1 
>>{'hi': 'wow', 'test': 'test1'} 
+0

Cela a l'air très intéressant, merci. Je me demande si cela peut être simplifié à la lumière de la partie mise à jour de la question, cependant. – AlexVhr

+0

en utilisant cette implémentation, vous pouvez soit changer le contenu dict comme d'habitude (comme dans le premier exemple) ou en utilisant un paramètre (comme dans le troisième exemple). D'ailleurs, peu importe quand et où vous mettez à jour le contenu dict –

+0

, si vous voulez avoir une sorte de journal des éléments modifiés, je vous recommande d'utiliser une liste de tuples où chaque ligne est une paire (valeur clé). De cette façon, si une valeur change deux fois, vous pouvez le voir. En outre, il n'y a aucune limite aux données que vous pouvez mettre sur cette structure, comme l'heure, l'ancienne valeur (bon pour une fonction d'annulation/rétablissement) ... –

0

Les propriétés (descripteurs, vraiment) n'aideront que si l'ensemble des attributs à surveiller est borné. Il suffit de classer la nouvelle valeur dans la méthode __set__() du descripteur.

Si l'ensemble des attributs est arbitraire ou non borné, vous devrez utiliser MyClass.__setattr__() à la place.

+1

Un morceau de code serait bien, merci – AlexVhr

0

Vous pouvez utiliser la property() fonction intégrée.

Ceci est préféré à l'écrasement __getattr__ et __setattr__, comme expliqué here.

class MyClass: 

     def __init__(self): 
      self.values = {} 
      self.changed_values = {} 

     def set_age(nr): 
      self.values['age'] = nr 
      self.changed_values['age'] = nr 

     def get_age(): 
      return self.values['age'] 

     age = property(get_age,set_age) 
+0

Mais dans ce cas, je dois écrire des getters et setters "statiques". Ce que je veux faire est de les créer dynamiquement. – AlexVhr

Questions connexes