2010-06-29 6 views
5

Ich versuche, Python @property Dekorator auf ein Dict in einer Klasse zu verwenden. Die Idee ist, dass ich einen bestimmten Wert (nennen Sie es "Nachricht") nach dem Zugriff gelöscht werden soll. Aber ich möchte auch einen anderen Wert (nennen Sie es "Last_message"), um die letzte Nachricht zu enthalten, und behalten Sie es, bis eine andere Nachricht gesetzt ist. In meinem Kopf, würde dieser Code funktionieren:Using @property Decorator auf dicts

>>> class A(object): 
...  def __init__(self): 
...    self._b = {"message": "", 
...      "last_message": ""} 
...  @property 
...  def b(self): 
...    b = self._b 
...    self._b["message"] = "" 
...    return b 
...  @b.setter 
...  def b(self, value): 
...    self._b = value 
...    self._b["last_message"] = value["message"] 
... 
>>> 

Allerdings scheint es nicht zu:

>>> a = A() 
>>> a.b["message"] = "hello" 
>>> a.b["message"] 
'' 
>>> a.b["last_message"] 
'' 
>>> 

bin ich nicht sicher, was ich falsch gemacht habe? Es scheint mir wie @property funktioniert nicht, wie ich es auf dicts erwarten würde, aber vielleicht mache ich etwas anderes grundsätzlich falsch?

Außerdem weiß ich, dass ich einfach einzelne Werte in der Klasse verwenden könnte. Aber das ist als eine Sitzung in einer Webanwendung implementiert und ich brauche es ein Diktat. Ich könnte entweder diese Arbeit machen, oder das ganze Session-Objekt dazu bringen, so zu tun, als ob es ein Diktat wäre, oder einzelne Variablen benutzen und es in den Rest der Code-Basis einarbeiten. Ich würde viel lieber nur das zur Arbeit bringen.

+2

sollten Sie Ihre Antwort in eine neue _ (Selbst-) Antwort anstatt in Ihre _question_ –

+0

BTW, anstelle von einem regulären "dict" Sie könnten daran interessiert sein, ['__slots__ = ['Nachricht', 'last_message '] '] (https://docs.python.org/2/reference/datamodel.html?highlight=slots#__slots__), wenn dies die einzigen zwei (festen) Schlüssel sind. Oder ändern Sie ein 'collections.namedtuple' –

Antwort

9
class MyDict(dict): 
    def __setitem__(self,key,value): 
     if key=='message': 
      dict.__setitem__(self,'message','') 
      dict.__setitem__(self,'last_message',value) 
     else: 
      dict.__setitem__(self,key,value) 

class A(object): 
    def __init__(self): 
      self._b = MyDict({"message": "", 
         "last_message": ""}) 
    @property 
    def b(self): 
     return self._b 

a=A() 
a.b['message']='hello' 
print(a.b['message']) 
# '' 
print(a.b['last_message']) 
# hello 

Wie ich glaube, Sie haben entdeckt, ist der Grund, warum Ihr Setter nicht funktioniert, weil

a.b['message']='hello' 

erste a.b zugreift, welche Anrufe die b der Getter der Eigenschaft, nicht sein Setter. Der Getter gibt das Diktat self._b zurück. Dann self._b['message']='hello' bewirkt, dass das Diktat __setitem__ aufgerufen wird. Um das Problem zu beheben, benötigen Sie ein spezielles dict (wie MyDict).

+0

Danke, ich habe ein spezielles Diktat gemacht und es funktioniert jetzt. Ich habe Eigenschaften komplett gelöscht und nur die gesamte Funktionalität in das Diktat verschoben (mit '__getitem__'). Ich werde auch meinen eigenen Code zu der Frage hinzufügen. –

+1

Sie (und @Carson) sollten 'super (MyDict, self) .__ settitem __ (Schlüssel, Wert)' anstelle von 'dict .__ stitem __ (self, key, value)' usw. verwenden (ansonsten werden Unterklassen von Ihnen mit mehreren Vorfahren verwendet) Ärger) –

1

Ich vermisse möglicherweise, was Sie hier versuchen, aber löst dies Ihr Problem?

class A(object): 
    def __init__(self): 
     self._b = {'message':'', 
        'last_message': ''} 

    @property 
    def b(self): 
     b = self._b.copy() 
     self._b['message'] = '' 
     return b 

    @b.setter 
    def b(self, value): 
     self._b['message'] = value 
     self._b['last_message'] = value 


if __name__ == "__main__": 
    a = A() 
    a.b = "hello" 
    print a.b 
    print a.b 
    print a.b["last_message"] 

$ python dictPropTest.py 
{'last_message': 'hello', 'message': 'hello'} 
{'last_message': 'hello', 'message': ''} 
hello 
+0

schließen, ich habe gerade entdeckt, dass die Zuweisung zu einem Schlüssel eines Setter nicht wirklich funktioniert. Ich dachte, dass 'a.b ['message'] =" hallo "' ein Diktat mit einem 'Nachricht'-Schlüssel an den Setter übergeben würde, aber das ist nicht der Fall. Aber was ich wirklich will, ist in der Lage zu sein, einem Schlüssel eines Setter zuzuweisen –