Reputation: 1024
I have defined a property area
and its getter in a parent class Shape
. In a child class Square
I would like to expand the getter functionality of area
. I wrote something which doesn't work:
class Shape:
def __init__(self):
self._area = None
@property
def area(self):
print('hello parent')
return self._area
# setter of `area` could be also defined here; hence in the child
# I would like to keep `area`, only decorating its getter.
class Square(Shape):
def __init__(self):
super(Square, self).__init__()
area = Shape.area.getter(self.dosomething())
def dosomething(self):
def new_func():
print('hello child')
Shape.area.fget(self)
return new_func
sq = Square()
When I run the code, I don't get the 'hello child':
>>> sq.area
hello parent
There are some obvious problems with my code above. For example, in Square
I should have
self.area = Shape.area.getter(self.dosomething())
rather than no self
. Then I would need to define the setter
of area
in parent...
After some fiddling, I came up with the following code,
class Shape:
def __init__(self):
self._area = None
@property
def area(self):
print('hello parent')
return self._area
class Square(Shape):
def __init__(self):
super(Square, self).__init__()
@Shape.area.getter
def area(self):
print('hello child')
Shape.area.fget(self)
sq = Square()
This time, it seems to do what I want:
>>> sq.area
hello child
hello parent
However, my ide tells me the line def area(self):
in Square
"overrides method in Shape".
Furthermore, IDE also says in Shape.area.fget(self)
, self
is an unexpected argument. Even though the code runs without error.
It feels like version 2 is a hack. Why is my ide complaining? I thought in version 2 I did not define a brand-new area
, just decorating the inherited area
's fget
, no?
Upvotes: 2
Views: 195
Reputation: 1024
After fiddling I arrive at this solution:
class Shape:
def __init__(self):
self._area = None
@property
def area(self):
print('hello parent')
return self._area
@area.setter
def area(self, val):
print('parent setter')
self._area = val
class Square(Shape):
def __init__(self):
super(Square, self).__init__()
@Shape.area.getter
def area(self):
print('hello child')
return super().area
@area.setter
def area(self, val):
print('setter in child')
Shape.area.fset(self, val) # IDE complains that val is unexpected. Why?
sq = Square()
It does what I wanted, with a remaining issue: ide complaines that val
is unexpected in the setter part in Square
(noted in the code). This runs without problems though. Getting rid of self
in that line raises error when running the code. I don't understand this. Feels like this is a hack.
I think the conclusion I arrive is that you are not supposed to expand on parent class's properties.
Upvotes: 0
Reputation: 106553
If you want to make the getter of the child class' area
property make use of the parent's area
property and expand on its value, in which case the child's getter function should call super()
to access the parent's property. As for making the child's setter make use of the parent's setter you would have to access the parent's setter via the fset
attribute of the parent class' property:
class Shape:
def __init__(self):
self._area = 'hello parent'
@property
def area(self):
return self._area
@area.setter
def area(self, value):
self._area = value
class Square(Shape):
@property
def area(self):
return super().area + ' and child'
@area.setter
def area(self, value):
Shape.area.fset(self, 'very ' + value)
sq = Square()
print(sq.area)
sq.area = 'new parent'
print(sq.area)
This outputs:
hello parent and child
very new parent and child
Alternatively, you can define new getter and setter methods in the child class and call property
on them:
class Square(Shape):
def area_getter(self):
return super().area + ' and child'
def area_setter(self, value):
Shape.area.fset(self, 'very ' + value)
area = property(area_getter, area_setter)
Upvotes: 1