2013-09-15 2 views
1

Я хочу иметь классы, которые автоматически отправляют уведомления подписчикам при изменении одного из их атрибутов. Так что, если я буду писать этот код:Оформление класса для контроля изменений атрибутов

@ChangeMonitor 
class ChangingClass(object): 

    def __init__(self, x): 
     self.x = x 


changer = ChangingClass(5) 
print("Going to change x.") 
changer.x = 6 
print("Going to not change x.") 
changer.x = 6 
print("End of program") 

Выход будет:

Going to change x 
Old x = 5, new x = 6 
Going to not change x. 
End of program. 

Мой вопрос заключается в том, как реализовать класс ChangeMonitor декоратора. В приведенном выше примере я предполагаю, что он напечатает строку, указывающую изменения атрибута, но в полезных целях он может отправлять уведомления подписанным объектам.

ответ

3

Вы должны были бы добавить __setattr__() method:

def ChangeMonitor(cls): 
    _sentinel = object() 
    old_setattr = getattr(cls, '__setattr__', None) 
    def __setattr__(self, name, value): 
     old = getattr(self, name, _sentinel) 
     if old not is _sentinel and old != value: 
      print "Old {0} = {1!r}, new {0} = {2!r}".format(name, old, value) 
     if old_setattr: 
      old_setattr(self, name, value) 
     else: 
      # Old-style class 
      self.__dict__[name] = value 

    cls.__setattr__ = __setattr__ 

    return cls 

Это должен обрабатывать существующие __setattr__ крючки, а также. _sentinel используется для того, чтобы None также использовалось как старое значение.

Демо:

>>> changer = ChangingClass(5) 
>>> changer.x = 6 
Old x = 5, new x = 6 
>>> changer.x = 6 
>>> # nothing printed 
... 
>>> changer.x = None 
Old x = 6, new x = None 
>>> changer.x = 6 
Old x = None, new x = 6 
+0

Я не вижу использование _sentinel или второй, если заявление. Если я выйду из _sentinel и замените инструкцию «if old_setattr» на «old_setattr (self, name, value)», то поведение будет одинаковым. Не могли бы вы объяснить это? Спасибо за вашу помощь, вы очень помогли! – user2302084

+0

Если вы замените часового на «Нет», вы не сможете определить, было ли новое значение «Нет» заменено новым значением. Вместо этого он будет неотличим от случая «без старой ценности». Я считаю, что классы старого стиля (не наследуемые от 'object') не имеют привязки' __setattr__' по умолчанию; Я сейчас не в состоянии проверить это; может быть излишне проверить, был ли найден крюк –

+0

Я вижу вашу точку зрения относительно дозорного. Я проверил код, не наследуя от объекта, и примеры дают тот же результат, поэтому я думаю, что вы правы, что тест для __setattr__ является избыточным. – user2302084