Reputation: 2914
Given an object foo
(to which i have access) of class A
(to which i have no access).
foo
has an attribute x, which is accessed by alot of parties which can also set foo.x
.
Is it somehow possible to replace foo.x
with a @property
-like such that assignments like
foo.x = "bar"
Will from then on invoke a function specified by me? If so, is it also possible to remove this property afterwards and replace it with something like e.g foo.x = "not a property"
again?
Please consider: I have no access to the class but only to the object.
Upvotes: 3
Views: 50
Reputation: 1121494
You can't put properties on an instance, no. You'll have to monkey-patch the class, or subclass it.
Monkey-patching would require you to store the original attribute somewhere on the instance still, using a different name:
def getter(self):
try:
return self._x
except AttributeError:
# access the attribute on the instance directly.
try:
return self.__dict__['x']
except KeyError:
raise AttributeError('x')
def setter(self, value):
self._x = value
foo._x = foo.x
type(foo).x = property(getter, setter)
This sets the property
object on the class. Now all instances of that class will have that property! To deal with this, the getter above falls back to trying to get the original x
attribute value from the instance __dict__
if no _x
attribute is present. This should ensure that existing instances continue to work.
Removing the property is as simple as deleting it:
del type(foo).x
Note that this will conflict with a class attribute (e.g. if type(foo).x
is an existing object).
Upvotes: 4