Это можно сделать - я могу придумать сложный способ, когда каждое присвоение «защищенному» свойству создает динамический класс-обертку для хранимого объекта.Этот класс будет контролировать доступ к любому «магическому» методу на объекте (то есть __setitem__, __setattr__, __iadd__, __isub__ и т. Д.).
Создание такого класса динамически интересно, но сложно и сложноработает правильно для любой ситуации.
Другой вариант, который я могу придумать, - создать копию каждого защищенного свойства, и при каждом доступе для чтения он будет проверять, равно ли сохраненное свойство его копии.Если нет, он пометит его как грязный.
Вместо использования свойств будет удобнее настроить класс дескриптора (который реализует поведение, подобное «свойству»)
from copy import deepcopy
class guarded_property(object):
# self.name attribute set here by the metaclass
def __set__(self, instance, value):
setattr(instance, "_" + self.name, value)
setattr(instance, "_" + self.name + "_copy", deepcopy(value))
setattr(instance, "_" + self.name + "_dirty", True)
def __get__(self, instance, owner):
return getattr (instance, "_" + self.name)
def clear(self, instance):
setattr(instance, "_" + self.name + "_dirty", False)
setattr(instance, "_" + self.name + "_copy", deepcopy(self.__get__(instance, None)))
def dirty(self, instance):
return getattr(instance, "_" + self.name + "_dirty") or not (getattr(instance, "_" + self.name + "_copy") == self.__get__(instance, None))
class Guarded(type):
def __new__(cls, name, bases, dict_):
for key, val in dict_.items():
if isinstance(val, guarded_property):
val.name = key
dict_[key + "_clear"] = (lambda v: lambda self: v.clear(self))(val)
dict_[key + "_dirty"] = (lambda v: property(lambda self: v.dirty(self)))(val)
return type.__new__(cls, name, bases, dict_)
if __name__ == "__main__":
class Example(object):
__metaclass__ = Guarded
a = guarded_property()
g = Example()
g.a = []
g.a_clear()
print g.a_dirty
g.a.append(5)
print g.a_dirty
g.a_clear()
print g.a_dirty