Использование @property декоратор на dicts - PullRequest
8 голосов
/ 29 июня 2010

Я пытаюсь использовать декоратор @property в Python для диктанта в классе.Идея состоит в том, что я хочу, чтобы определенное значение (назовите его 'message') было очищено после обращения к нему.Но я также хочу, чтобы другое значение (назовите его 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 не работает так, как я ожидал бы, когда речь идет о диктантах, но, может быть, я делаю что-то еще в корне неправильное?

Кроме того, я знаю, что могу просто использовать отдельные значениякласс.Но это реализовано как сеанс в веб-приложении, и мне нужно, чтобы он был диктом.Я мог бы либо заставить это работать, либо сделать весь объект сеанса, чтобы притвориться, что это диктат, или использовать отдельные переменные и взломать его на работоспособность в остальной части кода.Я бы предпочел просто заставить это работать.

Ответы [ 2 ]

12 голосов
/ 29 июня 2010
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 access a.b, который вызывает метод получения свойства b, а не его. Получатель возвращает дикт self._b. Тогда self._b['message']='hello' вызывает диктат __setitem__.

Итак, чтобы решить проблему, вам нужен специальный дикт (например, MyDict).

3 голосов
/ 29 июня 2010

Возможно, мне не хватает того, что вы пытаетесь сделать здесь, но решает ли это вашу проблему?

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