11

我正在尝试@property在类中的 dict 上使用 Python 的装饰器。这个想法是我希望某个值(称为“消息”)在被访问后被清除。但我还希望另一个值(称为“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不像我期望的那样在 dicts 上工作,但也许我做的其他事情根本上是错误的?

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

4

2 回答 2

17
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'

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

所以要解决这个问题,你需要一个特殊的字典(比如MyDict)。

于 2010-06-29T04:02:49.317 回答
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
于 2010-06-29T03:53:27.560 回答