Reputation: 3902
I have a class called Node
that has an importance
setter and getter, below:
class Node:
@property
def importance(self):
return self._importance
@importance.setter
def importance(self, new_importance):
if new_importance is not None:
new_importance = check_type_and_clean(new_importance, int)
assert new_importance >= 1 and new_importance <= 10
self._importance = new_importance
Later on, I have a class Theorem
that inherits from Node
. The only difference between a Theorem
and a Node
, as far as importance
is concerned, is that a Theorem
must have an importance
of at least 3
.
How can a Theorem inherit the importance
setter, but add on the additional constraint that importance >= 3
?
I tried to do it this way:
class Theorem(Node):
@importance.setter
def importance(self, new_importance):
self.importance = new_importance # hoping this would use the super() setter
assert self.importance >= 3
Upvotes: 18
Views: 10476
Reputation: 121976
Here is a completely different solution to the broader problem, with a lot less faffing around:
class Node:
MIN_IMPORTANCE = 1
MAX_IMPORTANCE = 10
@property
def importance(self):
return self._importance
@importance.setter
def importance(self, new_importance):
if new_importance is not None:
new_importance = check_type_and_clean(new_importance, int)
assert (new_importance >= self.MIN_IMPORTANCE and
new_importance <= self.MAX_IMPORTANCE)
self._importance = new_importance
class Theorem(Node):
MIN_IMPORTANCE = 3
# and that's all it takes!
To my mind, this expresses:
The only difference between a
Theorem
and aNode
, as far asimportance
is concerned, is that aTheorem
must have animportance
of at least3
.
a lot more clearly than overriding the property setter does.
Note that assert
is generally used for testing and debugging, rather than as part of the general program flow, and certainly not for things that you expect could happen; see e.g. Best practice for Python Assert.
Upvotes: 5
Reputation: 21883
You can refer to the existing property directly through the Node
class, and use the property's setter
method to create a new property from it:
class Theorem(Node):
@Node.importance.setter
def importance(self, new_importance):
# You can change the order of these two lines:
assert new_importance >= 3
Node.importance.fset(self, new_importance)
This will create a new property into Theorem
class that uses the getter method from Node.importance
but replaces the setter method with a different one.
That's how properties in general work: calling a property's setter
returns a new property with a custom setter, which usually just replaces the old property.
You can learn more about how properties work by reading this answer (and the question too).
Upvotes: 28
Reputation: 121976
One way to do this is by implementing a new property on Theorem
using the Node
getter, providing a new setter method and calling the Node
setter explicitly within it:
class Theorem(Node):
def _set_importance(self, new):
Node.importance.fset(self, new)
assert self.importance >= 3
importance = property(Node.importance.fget, _set_importance)
As far as I'm aware, this cannot be done with super
.
Per this bug report, you could do:
class Theorem(Node):
def _set_importance(self, new):
super(Theorem, Theorem).importance.fset(self, new)
assert self.importance >= 3
importance = property(Node.importance.fget, _set_importance)
However, this is clearly a bit awkward; the patch to allow super()
instead appears to be scheduled for Python 3.5 (due in September 2015).
Upvotes: 4