propiedades de Python y herencia

Tengo una clase base con una propiedad que (el método de obtención) 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 existen otras formas preferidas de hacerlo?

Simplemente prefiero repetir la property() , 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, la property 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 booston un par de métodos setter y deleter que se pueden usar para aplicar a las propiedades generales el acceso directo ya disponible para los de solo lectura:

 class C(object): @property def x(self): return self._x @x.setter def x(self, value): self._x = value 

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

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

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

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, una anulación se puede realizar fácilmente:

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

así que eso:

 >>> 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 jugando .

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 debe tener la idea.

Sí, esta es la manera de hacerlo; la statement de propiedad se ejecuta en el momento en que se ejecuta la definición de la clase principal, lo que significa que solo puede “ver” las versiones de los métodos que existen en la clase principal. Entonces, 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 trata 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 @ 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, una anulación se puede realizar fácilmente:

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

Me encontré con problemas para establecer una propiedad en una clase principal de una clase secundaria. 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)