I have a SuperClass which defines a property and it's setter, like so:
class A[object]:
def __init__[self]:
self._mode = None
@property
def mode[self]:
# to be overriden in subclass to implement the actual getter code
raise NotImplementedError
@mode.setter
def mode[self, value]:
# common assertions and input validations
self._set_mode[value]
def _set_mode[self, value]:
# to be overriden in subclass to implement the actual setter code
raise NotImplementedError
class B[A]:
@property
def mode[self]:
return self._mode
def _set_mode[self, value]:
self._mode = value
obj = B[]
obj.mode = 'test'
Which raises
obj.mode = 'test'
AttributeError: can't set attribute
It would seem that I have to register a setter in B. I'd usually do this like @A.mode.setter
, but that doesn't quite apply here as I don't actually want to define a new setter in B, just re-use the one from A.
Does anyone have a hint on how to solve this? Might be trivial, but I'm not seeing it right now :/
asked Mar 13, 2017 at 12:07
1
the getter and setter are stored as attributes of the property
object [respectively as .fget
and .fset
], so as soon as you overload the property in a child class you most explicitely provide both getter and setters,
ie:
class B[A]:
@property
def mode[self]:
return self._mode
@mode.setter
def mode[self, value]:
self._mode = value
So if you want to make the getter and/or setter overloadable without having to redeclare the property, you have to define a _get_mode
method and make your property's getter delegate to this method, just like you did for the setter.
class A[object]:
def __init__[self]:
self._mode = None
@property
def mode[self]:
return self._get_mode[]
def _get_mode[self]:
# to be overriden in subclass to implement the actual getter code
raise NotImplementedError
@mode.setter
def mode[self, value]:
# common assertions and input validations
self._set_mode[value]
def _set_mode[self, value]:
# to be overriden in subclass to implement the actual setter code
raise NotImplementedError
class B[A]:
def _get_mode[self]:
return self._mode
def _set_mode[self, value]:
self._mode = value
answered Mar 13, 2017 at 12:22
Analogously with using mode.setter
inside A
’s definition, this answer to a related question suggests to use a property of a base class to define a property on a subclass like so:
class B[A]:
@A.mode.getter # only this line is changed!
def mode[self]:
return self._mode
def _set_mode[self, value]:
self._mode = value
Here, mode.setter
will be the same as it was for A
, but we’ve replaced the getter.
answered Mar 2, 2021 at 22:02
arseniivarseniiv
982 silver badges7 bronze badges
It works for me this way
class A:
@property
def mode[self]:
raise NotImplemented
@mode.setter
def mode[self, value]:
raise NotImplemented
class B[A]:
@A.mode.setter
def mode[self, value]:
# your setter implement here
answered Aug 1, 2021 at 17:41
ganiularganiular
1531 silver badge7 bronze badges
Given a Although we could just reimplement the Two options: In either pattern, using However, accessing Python
@property
inheritance the right wayParent
class with value
property, Child
can inherit and overload the property while accessing Parent
property getter and setter.Child.value
property logic completely without using Parent.value
whatsover, this would violate the DRY principle and, more important, it wouldn't allow for
proper multiple inheritance [as show in the example property_inheritance.py
bellow].Child
redefines value
property completely, both getter and setter.Child
uses Parent.value
property, and only overloads setter. Parent
class must be referenced explicitly.Parent.value.getter
is as simple asParent.property.setter
is more verbose:super[Child, type[self]].value.fset[self, new_value]
It would be nice to just super[].value = new_value
but this won't work due to super
current implementation [as Python 3.7]. There is a Python Issue regarding this rather unintuitive behaviour.