I'm writing multiple classes with a common logic added to a bunch of attributes. This is a simplified version of the code:
class FooAspect:
_bar_prop = 'bar'
def __init__(self, bar_value: int):
self._bar = bar_value
@property
def bar(self) -> int:
return self._bar
@bar.setter
def bar(self, value: int) -> None:
self._bar = value
perfrom_action(self._bar_prop, value)
perform_action
always has similar form, and I would like to encapsulate it with a decorator. Essentially I'm looking for a way to write something like this:
# ... define @my_setter
class FooAspect:
# ...
@property
def bar(self) -> int:
return self._bar
@bar.my_setter(key='bar')
def bar(self, value: int) -> None:
self._bar = value
Is it possible to extend @property
or @prop.setter
to achieve this?
While copying and pasting the reference code of property
and making minor modifications would work as demonstrated by your answer, in the interest of code reuse you can subclass the property
class and call super()
to access methods of the parent class instead.
Also, the setter
function in your implementation is unnecessarily instantiating a new instance of MyProperty
, when it can reuse the current object by returning self._setter
:
class MyProperty(property):
def __set__(self, obj, value):
super().__set__(obj, value)
perform_action(self.key, value)
def _setter(self, fset):
obj = super().setter(fset)
obj.key = self.key
return obj
def setter(self, key):
self.key = key
return self._setter
so that:
class FooAspect:
@MyProperty
def bar(self) -> int:
return self._bar
@bar.setter(key='bar')
def bar(self, value: int) -> None:
self._bar = value
def perform_action(key, value):
print(key, value)
f = FooAspect()
f.bar = 'foo'
outputs:
bar foo