在dicts上使用@property装饰器

时间:2010-06-29 03:37:33

标签: python properties setter dictionary getter

我正在尝试在类的dict中使用Python的@property装饰器。我的想法是,我希望在访问后清除某个值(称之为“消息”)。但我还想要另一个值(称之为'last_message')来包含最后设置的消息,并保留它直到另一个消息被设置。在我看来,这段代码可行:

>>> 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"]
...
>>>

然而,它似乎没有:

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

我不确定我做错了什么?在我看来,@property不能像我期望的那样工作,但也许我在做其他根本错误的事情?

另外,我知道我可以在课堂上使用个别值。但这是作为Web应用程序中的会话实现的,我需要它作为一个词典。我可以使这个工作,或使整个会话对象假装它是一个字典,或使用单个变量并将其破解为整个代码库的其余工作。我宁愿让这个工作。

2 个答案:

答案 0 :(得分:12)

class MyDict(dict):
    def __setitem__(self, key, value):
        if key == 'message':
            super().__setitem__('message', '')
            super().__setitem__('last_message', value) 
        else:
            super().__setitem__(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

正如我认为你已经发现的那样,你的二传手不工作的原因是因为

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

首先访问a.b,它调用b属性的getter,而不是它的setter。 getter返回dict self._b。然后self._b['message']='hello'会导致dict的__setitem__被调用。

因此,要解决此问题,您需要一个特殊的字典(如MyDict)。

答案 1 :(得分:3)

我可能会想念你在这里尝试做什么,但这会解决你的问题吗?

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