Идея: заменить дескриптор свойства, чтобы разрешить установку для определенных объектов. Если значение не задано явно таким образом, вызывается средство получения исходного свойства.
Проблема в том, как сохранить явно заданные значения. Мы не можем использовать dict
ключи с исправленными объектами, так как 1) они не обязательно сопоставимы по идентичности; 2) это предотвращает сборку мусора для исправленных объектов. Для 1) мы могли бы написать Handle
, который обертывает объекты и переопределяет семантику сравнения по идентификатору, а для 2) мы могли бы использовать weakref.WeakKeyDictionary
. Однако я не мог заставить этих двоих работать вместе.
Поэтому мы используем другой подход к хранению явно установленных значений в самом объекте, используя «очень маловероятное имя атрибута». Конечно, все еще возможно, что это имя будет с чем-то конфликтовать, но это в значительной степени присуще таким языкам, как Python.
Это не сработает с объектами, у которых нет слота __dict__
. Однако аналогичная проблема может возникнуть и для weakrefs.
class Foo:
@property
def bar (self):
return 'original'
class Handle:
def __init__(self, obj):
self._obj = obj
def __eq__(self, other):
return self._obj is other._obj
def __hash__(self):
return id (self._obj)
_monkey_patch_index = 0
_not_set = object ()
def monkey_patch (prop):
global _monkey_patch_index, _not_set
special_attr = '$_prop_monkey_patch_{}'.format (_monkey_patch_index)
_monkey_patch_index += 1
def getter (self):
value = getattr (self, special_attr, _not_set)
return prop.fget (self) if value is _not_set else value
def setter (self, value):
setattr (self, special_attr, value)
return property (getter, setter)
Foo.bar = monkey_patch (Foo.bar)
f = Foo()
print (Foo.bar.fset)
print(f.bar) # baz
f.bar = 42 # MAGIC!
print(f.bar) # 42
person
doublep
schedule
23.07.2015
f.bar
не свойством (и если да, не затрагивая другие экземпляры?). Обратите внимание, что свойства, как и другие дескрипторы, хранятся в классе. - person jonrsharpe   schedule 23.07.2015f.bar
только в этом одном экземпляре. - person deceze♦   schedule 23.07.2015f.__dict__
, предоставив новый атрибутbar
, который будет просматриваться до того, как свойство будет найдено, но только для этого единственного экземпляра. - person jonrsharpe   schedule 23.07.2015Foo.bar = 42
... или вы просто хотите изменить свойство экземпляра? - person LittleQ   schedule 23.07.2015Foo
? @deceze - person LittleQ   schedule 23.07.2015Foo
и не контролирую его создание. Я также должен работать с этим экземпляром объекта, поскольку он отражается на других, у которых есть ссылка на него. - person deceze♦   schedule 23.07.2015Foo().__class__ = SubFoo
- person Markus Meskanen   schedule 23.07.2015