Как правило, можно добавлять или изменять атрибуты объекта по существу по своему усмотрению, но, по-видимому, невозможно изменить существующее свойство объекта для изменения базовых функций получения / установки / удаления.
Например, со следующим классом:
class Foo:
def __init__(self, x):
self._x = x
def get_x(self):
print("get_x function!")
return self._x
@property
def x(self):
print("x property getter!")
return self._x
Нетрудно заменить get_x
другой функцией:
In [1]: foo = Foo('foo')
...: foo.get_x()
get_x function!
Out[1]: 'foo'
In [2]: foo.get_x = lambda: 'something else'
...: foo.get_x()
Out[2]: 'something else'
И не сложно связать внешнюю функцию с объектом, так что он может принять self
:
def bind(instance, value):
return value.__get__(instance, instance.__class__)
Тогда:
In [3]: foo.get_x = bind(foo, lambda self: 'modified ' + self._x)
...: foo.get_x()
Out[3]: 'modified foo'
Мне известно, что это назначение только затеняет первоначальное определение, а не фактически заменяет его, но
Однако, если я попытаюсь заменить x
, свойство уже будет иметь контроль =
и setattr
. Я мог бы попробовать что-то вроде:
In [4]: foo.x = property(bind(foo, lambda self: 'modified ' + self._x))
AttributeError: can't set attribute
Но даже если бы это работало, это было бы бессмысленно, так как результатом был бы сам объект свойства, а не доступ к нему:
In [5]: foo.y = property(bind(foo, lambda self: 'modified ' + self._x))
...: foo.y
Out[5]: <property at 0x220e9780548>
И хотя изменение базового класса работает, я не хочу изменять всех экземпляров, только один:
In [6]: foo.__class__.x = property(lambda self: 'modified ' + self._x)
...: foo.x
Out[6]: 'modified foo'
In [7]: bar = Foo('bar')
...: bar.x # don't want this to have changed
Out[7]: 'modified bar'
Как я могу изменить базовый метод получения / установки / удаления свойства существующего объекта?