Last active
February 10, 2021 12:13
-
-
Save tnodet/d65b43636f0c169c65a1ec98513888fc to your computer and use it in GitHub Desktop.
Property inheritance done right in Python 3
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| class A: | |
| def __init__(self): | |
| self._prop = "bonjour" | |
| @property | |
| def prop(self): | |
| print("A.prop.getter") | |
| return self._prop | |
| @prop.setter | |
| def prop(self, value): | |
| print("A.prop.setter") | |
| self._prop = value | |
| class B(A): | |
| """Override getter and setter""" | |
| @property | |
| def prop(self): | |
| print("B.prop.getter") | |
| return super().prop # for getter, you can directly use super().prop | |
| # return super(B, self.__class__).prop.fget(self) # although fget would work | |
| @prop.setter | |
| def prop(self, value): | |
| print("B.prop.setter") | |
| # super().prop = value # this doesn't work! (AttributeError: 'super' object has no attribute 'prop') | |
| super(B, self.__class__).prop.fset(self, value) # for setter, you must use the fset method of the parent class's property | |
| # If you want to override only the getter or setter (but not both), you have to reference the parent class's property in the decorator | |
| class B1(A): | |
| """Override only getter""" | |
| @A.prop.getter | |
| def prop(self): | |
| print("B1.prop.getter") | |
| return super().prop | |
| class B2(A): | |
| """Override only setter""" | |
| @A.prop.setter | |
| def prop(self, value): | |
| print("B2.prop.setter") | |
| super(B2, self.__class__).prop.fset(self, value) | |
| # Note: don't use both '@ParentClass.prop.setter' and '@ParentClass.prop.getter' in a single child class, | |
| # because if the parent class itself inherited the property and only defined either the getter or the setter, | |
| # this can lead to the parent getter or setter not being called (the grandparent getter/setter is directly called). | |
| a = A() | |
| a.prop | |
| # A.prop.getter | |
| # 'bonjour' | |
| a.prop = "au revoir" | |
| # A.prop.setter | |
| a.prop | |
| # A.prop.getter | |
| # 'au revoir' | |
| b = B() | |
| b.prop = "salut" | |
| # B.prop.setter | |
| # A.prop.setter | |
| b.prop | |
| # B.prop.getter | |
| # A.prop.getter | |
| # 'salut' | |
| b1 = B1() | |
| b1.prop = 'only getter' | |
| # A.prop.setter | |
| b1.prop | |
| # B1.prop.getter | |
| # A.prop.getter | |
| # 'only getter' | |
| b2 = B2() | |
| b2.prop = 'only setter' | |
| # B2.prop.setter | |
| # A.prop.setter | |
| b2.prop | |
| # A.prop.getter | |
| # 'only setter' |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment