it-swarm.com.de

python-Eigenschaften und Vererbung

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?

53
Peter Hoffmann

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
65
piro

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.

11
Kamil Kisiel

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.

11
Mr. B

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.

7
James Bennett

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.

2

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'
2
Nizam Mohamed

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
2
Kozyarchuk

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)
0
andrew pate
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

0
Robin