Reputation: 111
I would like to inherit from a class containing a property x
, and then make this property read-only in the child class by overriding the setter. This does not work if __init__
in the parent class uses the original setter. Consider the following code.
class Parent:
def __init__(self, x=1):
# I want the following line to use the setter defined in the Parent
# class, even when __init__ is called from Child using super.
self.x = x
# Other initialization of Parent goes here.
@property
def x(self):
return self._x
@x.setter
def x(self, value):
"""Check that x is non-negative."""
if value < 0:
raise ValueError("x must be non-negative.")
self._x = value
class Child(Parent):
def __init__(self):
super().__init__() # Need this for initialization.
@property
def y(self):
return self._y
@y.setter
def y(self, value):
"""x can only be written to implicitly by setting y."""
self._y = value
self._x = abs(value)
@property
def x(self):
return self._x
@x.setter
def x(self, value):
raise AttributeError("Illegal access to x")
If I now try to instantiate Child
, I get AttributeError: Illegal access to x
because when the line self.x = x
is called, the x
setter of Child
is called instead of the x
setter of Parent
. How can I get it to use the setter of Parent
in a Pythonic way?
To be clear, when self.x = ...
appears in a method of Parent
, it should always make use of the x
setter in Parent
, and when self.x = ...
appears in a method of Child
, it should always make use of the x
setter in Child
, and thus raise an exception.
Upvotes: 0
Views: 102
Reputation: 111
I managed to solve the problem myself by swapping out
self.x = x
in Parent.__init__
with
Parent.x.fset(self, x)
I can also get rid of
@property
def x(self):
return self._x
in Child
if instead of @x.setter
, I use @Parent.x.setter
.
Upvotes: 1