Comment appeler une propriété de la classe de base si cette propriété est écrasée dans la classe dérivée?
-
06-07-2019 - |
Question
Je suis en train de changer certaines de mes classes, passant d'une utilisation intensive de getters et de setters à une utilisation plus pythonique des propriétés.
Mais à présent, je suis bloqué car certains de mes anciens getters ou setters appellent la méthode correspondante de la classe de base, puis effectuent autre chose. Mais comment cela peut-il être accompli avec des propriétés? Comment appeler le getter ou le setter de propriété dans la classe parente?
Bien sûr, l'appel de l'attribut lui-même donne une récursion infinie.
class Foo(object):
@property
def bar(self):
return 5
@bar.setter
def bar(self, a):
print a
class FooBar(Foo):
@property
def bar(self):
# return the same value
# as in the base class
return self.bar # --> recursion!
@bar.setter
def bar(self, c):
# perform the same action
# as in the base class
self.bar = c # --> recursion!
# then do something else
print 'something else'
fb = FooBar()
fb.bar = 7
La solution
Vous pourriez penser que vous pourriez appeler la fonction de classe de base appelée propriété:
class FooBar(Foo):
@property
def bar(self):
# return the same value
# as in the base class
return Foo.bar(self)
Bien que ce soit la chose la plus évidente à essayer, je pense - cela ne fonctionne pas car bar est une propriété et non un callable.
Mais une propriété est juste un objet, avec une méthode getter pour trouver l'attribut correspondant:
class FooBar(Foo):
@property
def bar(self):
# return the same value
# as in the base class
return Foo.bar.fget(self)
Autres conseils
Super devrait faire l'affaire:
return super().bar
Dans Python 2.x, vous devez utiliser la syntaxe plus détaillée:
return super(FooBar, self).bar
Il existe une alternative utilisant super
qui ne nécessite pas de référencer explicitement le nom de la classe de base.
Classe de base A:
class A(object):
def __init__(self):
self._prop = None
@property
def prop(self):
return self._prop
@prop.setter
def prop(self, value):
self._prop = value
class B(A):
# we want to extend prop here
pass
En B, accès au getter de propriétés de la classe parente A:
Comme d’autres ont déjà répondu, c’est:
super(B, self).prop
Ou en Python 3:
super().prop
Ceci retourne la valeur renvoyée par le getter de la propriété, pas le getter lui-même mais il suffit d'étendre le getter.
En B, accès au configurateur de propriétés de la classe parente A:
La meilleure recommandation que j'ai vue jusqu'à présent est la suivante:
A.prop.fset(self, value)
Je crois que celui-ci est meilleur:
super(B, self.__class__).prop.fset(self, value)
Dans cet exemple, les deux options sont équivalentes, mais l'utilisation de super présente l'avantage d'être indépendante des classes de base de B
. Si B
devait hériter d'une classe C
étendant également la propriété, vous ne seriez pas obligé de mettre à jour le code de B
.
Code complet de B étendant la propriété de A:
class B(A):
@property
def prop(self):
value = super(B, self).prop
# do something with / modify value here
return value
@prop.setter
def prop(self, value):
# do something with / modify value here
super(B, self.__class__).prop.fset(self, value)
Une mise en garde:
À moins que votre propriété ne possède pas de setter, vous devez définir à la fois le setter et le getter dans B
même si vous ne modifiez que le comportement de l'un d'entre eux.
essayer
@property
def bar:
return super(FooBar, self).bar
Bien que je ne sache pas si Python prend en charge l’appel de la propriété de classe de base. Une propriété est en réalité un objet appelable qui est configuré avec la fonction spécifiée, puis remplace ce nom dans la classe. Cela pourrait facilement signifier qu’il n’ya pas de super-fonction disponible.
Vous pouvez toujours changer votre syntaxe pour utiliser la fonction property () bien que:
class Foo(object):
def _getbar(self):
return 5
def _setbar(self, a):
print a
bar = property(_getbar, _setbar)
class FooBar(Foo):
def _getbar(self):
# return the same value
# as in the base class
return super(FooBar, self)._getbar()
def bar(self, c):
super(FooBar, self)._setbar(c)
print "Something else"
bar = property(_getbar, _setbar)
fb = FooBar()
fb.bar = 7
class Base(object):
def method(self):
print "Base method was called"
class Derived(Base):
def method(self):
super(Derived,self).method()
print "Derived method was called"
d = Derived()
d.method()
(à moins que je ne manque quelque chose dans votre explication)