Reputation: 4782
I want to call a function when an object attribute is set:
class MyClass():
myattrib = None
def __setattr__(self, prop, val):
self.myattrib = val
print("setting myattrib")
x = MyClass()
x.myattrib = "something"
The problem is, that this creates an infinite recursion.
The idea is to call a function when a member variable is set (and actually set that member variable), but at the same time run extra code (showcased with the print()
statement in the example above).
The other obvious way to do this, is using set_attrib()
functions, as is common in Java, but I'd like to do it the pythonic way, and set the attributes directly, but at the same time running extra code.
Upvotes: 2
Views: 5640
Reputation: 1124378
Call the base version via super()
:
class MyClass(object):
myattrib = None
def __setattr__(self, prop, val):
super().__setattr__('myattrib', val)
print("setting myattrib")
You probably do not want to ignore the prop
argument here, it is not necessarily 'myattrib'
that is being set.
However, consider using a property instead of intercepting all attribute setting:
class MyClass(object):
_myattrib = None
@property:
def myattrib(self):
return self._myattrib
@myattrib.setter
def myattrib(self, val):
self._myattrib = val
print("setting myattrib")
I added object
as a base-class; this is the default in Python 3, but a requirement for super()
and property
objects to work in Python 2.
Upvotes: 5
Reputation: 104792
If you want to do a specific thing when any attribute is set, use __setattr__
and call the inherited version using super
for the actual assignment:
def __setattr__(self, prop, val):
super().__setattr__(prop, val)
print("setting {} to {!r}".format(prop, val)
If you only want to do something special for one attribute (not all attributes), you should probably use a property
instead:
class MyClass():
@property
def some_attribute(self):
return self._val
@some_attribute.setter
def some_attribute(self, value):
self._val = value
print("set some_attribute to {!r}".format(value))
Upvotes: 3