Je change certaines de mes classes d'une utilisation extensive des getters et setters à une utilisation plus pythonique des propriétés.
Mais maintenant je suis bloqué parce que certains de mes précédents getters ou setters appelleraient la méthode correspondante de la classe de base, puis effectueraient autre chose. Mais comment cela peut-il être accompli avec des propriétés? Comment appeler la propriété getter ou setter dans la classe parent?
Bien sûr, le simple fait d'appeler 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 source
Foo.bar.fset(self, c)
un passeur hérité? Pourquoi pasFoo.bar.fset(c)
- sans le «moi» - je pensais que c'était implicitement passé?self
get implique de la chaîneFoo.bar.fset
?foo = Foo()
\foo.bar(c)
, aucun self n'est passé, mais bar () le reçoit de Python. Je ne suis pas un expert Python, plus ou moins un débutant aussi. C'est juste une pensée.self
n'est transmise implicitement que lorsque la méthode est appelée sur une instance d'une classe. Par exemple, si j'ai une classeA
avec une méthodeb(self, arg)
et que je crée une instancec = A()
, alors l'appelc.b(arg)
est équivalent àA.b(c, arg)
Super devrait faire l'affaire:
return super().bar
Dans Python 2.x, vous devez utiliser la syntaxe la plus verbeuse:
return super(FooBar, self).bar
la source
AttributeError
.Il existe une alternative d'utilisation
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éder au getter de propriété de la classe parent A:
Comme d'autres l'ont déjà répondu, c'est:
Ou en Python 3:
Cela retourne la valeur retournée par le getter de la propriété, pas le getter lui-même mais c'est suffisant pour étendre le getter.
En B, accéder au setter de propriétés de la classe parent A:
La meilleure recommandation que j'ai vue jusqu'à présent est la suivante:
Je pense que celui-ci est meilleur:
Dans cet exemple, les deux options sont équivalentes mais l'utilisation de super a l'avantage d'être indépendante des classes de base de
B
. Si vous deviezB
hériter d'uneC
classe étendant également la propriété, vous n'auriez pas à mettre à jourB
le code de.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:
Sauf si votre propriété n'a pas de setter, vous devez définir à la fois le setter et le getter
B
même si vous ne modifiez que le comportement de l'un d'eux.la source
super(B, self.__class__)
fonctionne exactement avecsuper(class, class)
? Où est-il documenté?essayer
@property def bar: return super(FooBar, self).bar
Bien que je ne sois pas sûr que python prenne en charge l'appel de la propriété de classe de base. Une propriété est en fait 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'y a pas de super fonction disponible.
Vous pouvez toujours changer votre syntaxe pour utiliser la fonction property ():
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
la source
Quelques petites améliorations à la réponse de Maxime :
__class__
pour éviter d'écrireB
. Notez qu'ilself.__class__
s'agit du type d'exécution deself
, mais__class__
sansself
le nom de la définition de classe englobante.super()
est un raccourci poursuper(__class__, self)
.__set__
au lieu defset
. Ce dernier est spécifique àproperty
s, mais le premier s'applique à tous les objets de type propriété (descripteurs).class B(A): @property def prop(self): value = super().prop # do something with / modify value here return value @prop.setter def prop(self, value): # do something with / modify value here super(__class__, self.__class__).prop.__set__(self, value)
la source
Vous pouvez utiliser le modèle suivant:
class Parent(): def __init__(self, value): self.__prop1 = value #getter @property def prop1(self): return self.__prop1 #setter @prop1.setter def prop1(self, value): self.__prop1 = value #deleter @prop1.deleter def prop1(self): del self.__prop1 class Child(Parent): #getter @property def prop1(self): return super(Child, Child).prop1.__get__(self) #setter @prop1.setter def prop1(self, value): super(Child, Child).prop1.__set__(self, value) #deleter @prop1.deleter def prop1(self): super(Child, Child).prop1.__delete__(self)
Remarque! Toutes les méthodes de propriété doivent être redéfinies ensemble. Si vous ne souhaitez pas redéfinir toutes les méthodes, utilisez plutôt le modèle suivant:
class Parent(): def __init__(self, value): self.__prop1 = value #getter @property def prop1(self): return self.__prop1 #setter @prop1.setter def prop1(self, value): self.__prop1 = value #deleter @prop1.deleter def prop1(self): del self.__prop1 class Child(Parent): #getter @Parent.prop1.getter def prop1(self): return super(Child, Child).prop1.__get__(self) #setter @Parent.prop1.setter def prop1(self, value): super(Child, Child).prop1.__set__(self, value) #deleter @Parent.prop1.deleter def prop1(self): super(Child, Child).prop1.__delete__(self)
la source
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)
la source