Domanda

Ho una classe base con una proprietà che (il metodo get) voglio sovrascrivere nella sottoclasse. Il mio primo pensiero è stato qualcosa del tipo:

class Foo(object):
    def _get_age(self):
        return 11

    age = property(_get_age)


class Bar(Foo):
    def _get_age(self):
        return 44

Questo non funziona (la sottoclasse bar.age restituisce 11). Ho trovato una soluzione con un'espressione lambda che funziona:

age = property(lambda self: self._get_age())

Quindi questa è la soluzione giusta per usare le proprietà e sovrascriverle in una sottoclasse, o ci sono altri modi preferiti per farlo?

È stato utile?

Soluzione

Preferisco semplicemente ripetere la proprietà () e ripeterai il decoratore @classmethod quando esegui l'override di un metodo di classe.

Anche se questo sembra molto dettagliato, almeno per gli standard Python, potresti notare:

1) per proprietà di sola lettura, proprietà può essere usato come decoratore:

class Foo(object):
    @property
    def age(self):
        return 11

class Bar(Foo):
    @property
    def age(self):
        return 44

2) in Python 2.6, le proprietà sono cresciute in una coppia di metodi setter e deleter che possono essere utilizzati per applicare alle proprietà generali il collegamento già disponibile per quelli di sola lettura:

class C(object):
    @property
    def x(self):
        return self._x

    @x.setter
    def x(self, value):
        self._x = value

Altri suggerimenti

Non sono d'accordo sul fatto che la risposta scelta sia il modo ideale per consentire l'override dei metodi di proprietà. Se ti aspetti che i getter e i setter vengano sovrascritti, puoi usare lambda per fornire accesso a sé, con qualcosa come lambda self: self. & Lt; property func > .

Funziona (almeno) per le versioni Python da 2.4 a 3.6.

Se qualcuno conosce un modo per farlo usando la proprietà come decoratore invece che come chiamata di proprietà diretta (), mi piacerebbe ascoltarlo!

Esempio:

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))

In questo modo, una sostituzione può essere facilmente eseguita:

class Bar(Foo):
    def _get_meow(self):
        return super(Bar, self)._get_meow() + ', altered by a Bar'

in modo che:

>>> 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"

L'ho scoperto su geek in gioco .

Un altro modo per farlo, senza dover creare classi aggiuntive. Ho aggiunto un metodo set per mostrare cosa fai se si ignora solo uno dei due:

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)

Questo è un esempio piuttosto ingegnoso, ma dovresti avere l'idea.

Sì, questo è il modo di farlo; la dichiarazione di proprietà viene eseguita al momento dell'esecuzione della definizione della classe genitore, il che significa che può solo " vedere " le versioni dei metodi esistenti nella classe genitore. Pertanto, quando si ridefiniscono uno o più di questi metodi su una classe figlio, è necessario dichiarare nuovamente la proprietà utilizzando la versione dei metodi della classe figlio.

Sono d'accordo con la tua soluzione, che sembra un metodo di template al volo. Questo articolo tratta il tuo problema e fornisce esattamente la tua soluzione.

Qualcosa del genere funzionerà

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

Come per @ mr-b ma con decoratore.

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)

In questo modo, una sostituzione può essere facilmente eseguita:

class Bar(Foo):
    def _get_meow(self):
        return super(Bar, self)._get_meow() + ', altered by a Bar'

Ho riscontrato problemi durante l'impostazione di una proprietà in una classe genitore da una classe figlio. Il seguente workround estende una proprietà di un genitore ma lo fa chiamando direttamente il metodo _set_age del genitore. Le rughe dovrebbero essere sempre corrette. È un po 'javathonic però.

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)
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top