Wie eine Eigenschaft der Basisklasse aufrufen, wenn diese Eigenschaft in der abgeleiteten Klasse überschrieben wird?
-
06-07-2019 - |
Frage
Ich bin einige Klassen von mir aus einer umfangreichen Verwendung von Getter und Setter zu einer pythonic Verwendung von Eigenschaften zu verändern.
Aber jetzt bin ich stecken, weil einige meiner früheren Getter oder Setter nennen würde die entsprechende Methode der Basisklasse, und dann etwas anderes ausführen. Aber wie kann dies mit Eigenschaften erreicht werden? Wie die Eigenschaft Getter oder Setter in der übergeordneten Klasse nennen?
Natürlich ruft nur das Attribut selbst gibt unendliche Rekursion.
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
Lösung
Man könnte denken, Sie die Basisklasse Funktion aufrufen kann, die durch Eigenschaft genannt wird:
class FooBar(Foo):
@property
def bar(self):
# return the same value
# as in the base class
return Foo.bar(self)
Obwohl dies das Selbstverständlichste zu versuchen Ich denke, -. es funktioniert nicht, weil bar eine Eigenschaft ist, kein aufrufbar
Aber eine Eigenschaft ist nur ein Objekt, mit einer Getter-Methode das entsprechende Attribut zu finden:
class FooBar(Foo):
@property
def bar(self):
# return the same value
# as in the base class
return Foo.bar.fget(self)
Andere Tipps
super sollte den Trick tun:
return super().bar
In Python 2.x müssen Sie die ausführlichere Syntax:
return super(FooBar, self).bar
Es gibt eine Alternative mit super
, die nicht explizit benötigt, um die Basisklasse Namen zu verweisen.
Basisklasse 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
In B, die Eigenschaft Getter der Elternklasse A den Zugriff auf:
Wie andere haben bereits beantwortet, es ist:
super(B, self).prop
oder in Python 3:
super().prop
Dies gibt den Wert vom Getter der Eigenschaft zurückgegeben, nicht der Getter selbst, sondern es ist ausreichend, um den Getter zu verlängern.
In B, die Eigenschaft Setter der Elternklasse A den Zugriff auf:
Die beste Empfehlung, die ich bisher gesehen habe, ist die folgende:
A.prop.fset(self, value)
Ich glaube, das ist besser:
super(B, self.__class__).prop.fset(self, value)
In diesem Beispiel sind beide Optionen gleichwertig, aber Super haben den Vorteil, von den Basisklassen von B
unabhängig zu sein. Wenn B
von einer C
Klasse erben waren auch die Eigenschaft erstreckt, würden Sie nicht müssen B
den Code aktualisieren.
Vollständiger Code B A Eigentum erstreckt:
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)
Eine Warnung:
Es sei denn, Ihr Eigentum keinen Setter haben, müssen Sie sowohl die Setter und Getter in B
definieren, auch wenn Sie nur das Verhalten einer von ihnen ändern.
Versuch
@property
def bar:
return super(FooBar, self).bar
Obwohl ich nicht sicher bin, ob Python unterstützt die Basisklasse Eigenschaft aufrufen. Eine Eigenschaft ist tatsächlich ein aufrufbare Objekt, das mit der Funktion oben angegeben gesetzt und ersetzt dann diesen Namen in der Klasse. Dies könnte leicht dazu führen, dass es keine Super-Funktion zur Verfügung.
Sie können immer schalten Sie Ihre Syntax obwohl die Eigenschaft () Funktion zu verwenden:
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()
(das ist, wenn ich etwas von Ihrer Erklärung fehle)