2010-06-29 14 views
5

Estoy tratando de usar el decorador de Python @property en un dict en una clase. La idea es que quiero que se borre cierto valor (llámalo 'mensaje') después de que se acceda a él. Pero también quiero otro valor (llámalo 'last_message') para contener el último mensaje configurado y mantenlo hasta que se establezca otro mensaje. En mi mente, el código funcionaría:Usando @property decorator en los 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"] 
... 
>>> 

Sin embargo, no parece:

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

No estoy seguro de lo que he hecho mal? Me parece que @property no funciona como lo esperaría en los dicts, pero ¿tal vez estoy haciendo algo más fundamentalmente erróneo?

Además, sé que podría usar valores individuales en la clase. Pero esto se implementa como una sesión en una aplicación web y necesito que sea un dict. Podría hacer que esto funcione o hacer que todo el objeto de la sesión pretenda ser un dict, o usar variables individuales y modificarlas para que funcionen en el resto de la base de código. Prefiero simplemente hacer que esto funcione.

+2

debe poner su respuesta en una _ _respuesta_automática_ en vez de en su _question_ –

+0

btw, en lugar de un 'dict' normal que podría interesarle usar [' __slots__ = ['message', 'last_message '] '] (https://docs.python.org/2/reference/datamodel.html?highlight=slots#__slots__) si esas son las únicas dos claves (fijas). O bien, modifique 'collections.namedtuple' –

Respuesta

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 

Como creo que usted ha descubierto, por lo cual su colocador no estaba funcionando es porque

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

primera accesos a.b, que llama al b propiedad getter, no su setter. El getter devuelve el dict self._b. Entonces self._b['message']='hello' hace que se llame al dict __setitem__.

Para solucionar el problema, necesita una dict especial (como MyDict).

+0

Gracias, hice un dict especial y ahora está funcionando. Sin embargo, abandoné las propiedades y simplemente moví toda la funcionalidad al dict (con '__getitem__'). Agregaré mi propio código a la pregunta también. –

+1

Usted (y @Carson) deberían usar 'super (MyDict, self) .__ setitem __ (clave, valor)' en lugar de 'dict .__ setitem __ (self, key, value)' etc (de lo contrario, se encontrarán subclases suyos con antepasados ​​múltiples) problema) –

1

Me puede estar faltando lo que está tratando de hacer aquí, pero ¿esto resuelve su problema?

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

close, de hecho descubrí que la asignación a una clave de un setter no funciona realmente. Estaba pensando que 'a.b ['message'] =" hello "' pasaría un dict que contiene una clave de 'mensaje' al colocador, pero ese no es el caso. Pero lo que realmente quiero es poder asignarle una clave a un setter –