Ich habe eine Basisklasse mit einer Eigenschaft, die (die Methode get) in der Unterklasse überschrieben werden soll. Mein erster Gedanke war so etwas wie:
class Foo(object):
def _get_age(self):
return 11
age = property(_get_age)
class Bar(Foo):
def _get_age(self):
return 44
Dies funktioniert nicht (Unterklasse bar.age gibt 11 zurück). Ich habe eine Lösung mit einem Lambda-Ausdruck gefunden, die funktioniert:
age = property(lambda self: self._get_age())
Ist dies also die richtige Lösung, um Eigenschaften zu verwenden und sie in einer Unterklasse zu überschreiben, oder gibt es andere Möglichkeiten, dies zu tun?
Ich bevorzuge einfach die property()
zu wiederholen, ebenso wie Sie den @classmethod
-Dekorator wiederholen, wenn Sie eine Klassenmethode überschreiben.
Obwohl dies zumindest für Python-Standards sehr ausführlich erscheint, stellen Sie möglicherweise Folgendes fest:
1) Für schreibgeschützte Eigenschaften kann property
als Dekorator verwendet werden:
class Foo(object):
@property
def age(self):
return 11
class Bar(Foo):
@property
def age(self):
return 44
2) In Python 2.6 wuchsen in properties ein Methodenpaarsetter
und deleter
, mit dem auf die allgemeinen Eigenschaften die bereits für schreibgeschützte Methoden verfügbare Verknüpfung angewendet werden kann:
class C(object):
@property
def x(self):
return self._x
@x.setter
def x(self, value):
self._x = value
Eine andere Möglichkeit, dies zu tun, ohne zusätzliche Klassen erstellen zu müssen. Ich habe eine Set-Methode hinzugefügt, um zu zeigen, was Sie tun, wenn Sie nur eine der beiden Einstellungen überschreiben:
class Foo(object):
def _get_age(self):
return 11
def _set_age(self, age):
self._age = age
age = property(_get_age, _set_age)
class Bar(Foo):
def _get_age(self):
return 44
age = property(_get_age, Foo._set_age)
Dies ist ein ziemlich erfundenes Beispiel, aber Sie sollten die Idee bekommen.
Ich stimme nicht zu, dass die gewählte Antwort die ideale Methode ist, um die Eigenschaftsmethoden zu überschreiben. Wenn Sie erwarten, dass die Getter und Setter überschrieben werden, können Sie Lambda verwenden, um den Zugriff auf sich selbst zu ermöglichen, beispielsweise mit lambda self: self.<property func>
.
Dies funktioniert (zumindest) für die Python-Versionen 2.4 bis 3.6.
Wenn jemand einen Weg kennt, dies zu tun, indem Sie property als Dekorateur und nicht als direkten property () - Aufruf verwenden, würde ich das gerne hören!
Beispiel:
class Foo(object):
def _get_meow(self):
return self._meow + ' from a Foo'
def _set_meow(self, value):
self._meow = value
meow = property(fget=lambda self: self._get_meow(),
fset=lambda self, value: self._set_meow(value))
Auf diese Weise kann eine Überschreibung leicht durchgeführt werden:
class Bar(Foo):
def _get_meow(self):
return super(Bar, self)._get_meow() + ', altered by a Bar'
damit:
>>> foo = Foo()
>>> bar = Bar()
>>> foo.meow, bar.meow = "meow", "meow"
>>> foo.meow
"meow from a Foo"
>>> bar.meow
"meow from a Foo, altered by a Bar"
Ich habe dies auf geek at play entdeckt.
Ja, das ist der Weg, dies zu tun. Die Eigenschaftsdeklaration wird zu dem Zeitpunkt ausgeführt, zu dem die Definition der übergeordneten Klasse ausgeführt wird. Dies bedeutet, dass nur die Versionen der auf der übergeordneten Klasse vorhandenen Methoden "gesehen" werden können. Wenn Sie also eine oder mehrere dieser Methoden für eine untergeordnete Klasse neu definieren, müssen Sie die Eigenschaft mit der Version der untergeordneten Klasse der Methode (n) erneut deklarieren.
Ich stimme mit Ihrer Lösung überein, die scheinbar eine On-the-Fly-Vorlagenmethode ist. Dieser Artikel beschäftigt sich mit Ihrem Problem und bietet genau Ihre Lösung.
Wie @ mr-b , jedoch mit Dekorator
class Foo(object):
def _get_meow(self):
return self._meow + ' from a Foo'
def _set_meow(self, value):
self._meow = value
@property
def meow(self):
return self._get_meow()
@meow.setter
def meow(self, value):
self._set_meow(value)
Auf diese Weise kann eine Überschreibung leicht durchgeführt werden:
class Bar(Foo):
def _get_meow(self):
return super(Bar, self)._get_meow() + ', altered by a Bar'
So etwas wird funktionieren
class HackedProperty(object):
def __init__(self, f):
self.f = f
def __get__(self, inst, owner):
return getattr(inst, self.f.__name__)()
class Foo(object):
def _get_age(self):
return 11
age = HackedProperty(_get_age)
class Bar(Foo):
def _get_age(self):
return 44
print Bar().age
print Foo().age
Ich hatte Probleme mit der Einstellung einer Eigenschaft in einer übergeordneten Klasse aus einer untergeordneten Klasse. Der folgende Workround erweitert eine Eigenschaft eines übergeordneten Elements, ruft jedoch die Methode _set_age des übergeordneten Elements direkt auf. Faltenbildung sollte immer korrekt sein. Es ist ein bisschen javathonic.
import threading
class Foo(object):
def __init__(self):
self._age = 0
def _get_age(self):
return self._age
def _set_age(self, age):
self._age = age
age = property(_get_age, _set_age)
class ThreadsafeFoo(Foo):
def __init__(self):
super(ThreadsafeFoo, self).__init__()
self.__lock = threading.Lock()
self.wrinkled = False
def _get_age(self):
with self.__lock:
return super(ThreadsafeFoo, self).age
def _set_age(self, value):
with self.__lock:
self.wrinkled = True if value > 40 else False
super(ThreadsafeFoo, self)._set_age(value)
age = property(_get_age, _set_age)
class Foo:
# Template method
@property
def age(self):
return self.dothis()
# Hook method of TM is accessor method of property at here
def dothis(self):
return 11
class Bar(Foo):
def dothis(self):
return 44
Wie Nizam Mohamed, nur um das zu erwähnen Styleguide 2.13.4 unter Verwendung sowohl der Template-Methode als auch der Eigenschaft