Pregunta

Tengo una clase base con una propiedad que (el método get) quiero sobrescribir en la subclase. Mi primer pensamiento fue algo como:

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

    age = property(_get_age)


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

Esto no funciona (la subclase bar.age devuelve 11). Encontré una solución con una expresión lambda que funciona:

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

Entonces, ¿es esta la solución correcta para usar propiedades y sobrescribirlas en una subclase, o hay otras formas preferidas de hacerlo?

¿Fue útil?

Solución

Simplemente prefiero repetir la propiedad () , así como usted repetirá el decorador @classmethod al anular un método de clase.

Si bien esto parece muy detallado, al menos para los estándares de Python, puede notar:

1) para propiedades de solo lectura, propiedad se puede utilizar como decorador:

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

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

2) en Python 2.6, las propiedades crecieron un par de métodos setter y deleter que se pueden usar para aplicar a las propiedades generales el acceso directo ya disponible para las de solo lectura:

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

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

Otros consejos

No estoy de acuerdo con que la respuesta elegida sea la forma ideal de permitir anular los métodos de propiedad. Si espera que se anulen a los captadores y establecedores, entonces puede usar lambda para proporcionar acceso a sí mismo, con algo como lambda self: self. & Lt; property func > .

Esto funciona (al menos) para las versiones 2.4 a 3.6 de Python.

Si alguien sabe cómo hacerlo con el uso de la propiedad como decorador en lugar de como una llamada directa a la propiedad (), ¡me gustaría escucharlo!

Ejemplo:

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

De esta manera, se puede realizar una anulación fácilmente:

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

para que:

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

Descubrí esto en geek en juego .

Otra forma de hacerlo, sin tener que crear ninguna clase adicional. He agregado un método de configuración para mostrar lo que haces si solo anulas uno de los dos:

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)

Este es un ejemplo bastante artificial, pero deberías tener una idea.

Sí, esta es la manera de hacerlo; la declaración de propiedad se ejecuta en el momento en que se ejecuta la definición de la clase padre, lo que significa que solo puede " ver " Las versiones de los métodos que existen en la clase padre. Por lo tanto, cuando redefine uno o más de esos métodos en una clase secundaria, deberá volver a declarar la propiedad utilizando la versión de la (s) método (s) de la clase secundaria.

Estoy de acuerdo con su solución, que parece ser un método de plantilla sobre la marcha. Este artículo se ocupa de su problema y proporciona exactamente su solución.

Algo como esto funcionará

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

Igual que los @ mr-b pero con decorador.

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)

De esta manera, se puede realizar una anulación fácilmente:

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

Me encontré con problemas al establecer una propiedad en una clase padre desde una clase hija. La siguiente ronda de trabajo amplía una propiedad de un padre pero lo hace llamando directamente al método _set_age del padre. Arrugado siempre debe ser correcto. Aunque es un poco 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)
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top