Sebastian Hoffmann
Sebastian Hoffmann

Reputation: 2914

Define properties for object instances

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

Answers (1)

Martijn Pieters
Martijn Pieters

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

Related Questions