Comment appeler une propriété de la classe de base si cette propriété est écrasée dans la classe dérivée?

StackOverflow https://stackoverflow.com/questions/1021464

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
Était-ce utile?

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)

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top