[respuesta escrita basada en Python 3.4; la sintaxis de metaclase difiere en 2, pero creo que la técnica seguirá funcionando]
Puede hacer esto con una metaclase ... principalmente. Dappawit es casi obras, pero creo que tiene un defecto:
class MetaFoo(type):
@property
def thingy(cls):
return cls._thingy
class Foo(object, metaclass=MetaFoo):
_thingy = 23
Esto se consigue un ClassProperty de Foo, pero hay un problema ...
print("Foo.thingy is {}".format(Foo.thingy))
# Foo.thingy is 23
# Yay, the classmethod-property is working as intended!
foo = Foo()
if hasattr(foo, "thingy"):
print("Foo().thingy is {}".format(foo.thingy))
else:
print("Foo instance has no attribute 'thingy'")
# Foo instance has no attribute 'thingy'
# Wha....?
¿Qué demonios está pasando aquí? ¿Por qué no puedo acceder a la propiedad de la clase desde una instancia?
Me estaba dando vueltas en esto por bastante tiempo antes de encontrar lo que creo que es la respuesta. @properties Python son un subconjunto de los descriptores, y, a partir de la (el énfasis es mío) descriptor documentation: Comportamiento
El valor por defecto para el acceso atributo es conseguir, establecer o eliminar el atributo del diccionario de un objeto. Por ejemplo, a.x
tiene una cadena de búsqueda de comenzando con a.__dict__['x']
, entonces type(a).__dict__['x']
, y continuando a través de las clases base de type(a)
excluyendo metaclases.
Así que el orden de resolución del método no incluye nuestras propiedades de clase (o cualquier otra cosa definida en la metaclase). Es es posible hacer una subclase del decorador de propiedades incorporado que se comporta de manera diferente, pero (cita requerida) Tengo la impresión de que los desarrolladores de Google tenían una buena razón (que no entiendo) para hacerlo camino.
Eso no significa que no tengamos suerte; podemos acceder a las propiedades de la clase en sí muy bien ... y podemos conseguir la clase de type(self)
dentro de la instancia, que podemos utilizar para hacer @property despachadores:
class Foo(object, metaclass=MetaFoo):
_thingy = 23
@property
def thingy(self):
return type(self).thingy
Ahora Foo().thingy
funciona como está previsto tanto para la clase y las instancias! También continuará haciendo lo correcto si una clase derivada reemplaza su subyacente _thingy
(que es el caso de uso que me consiguió en esta búsqueda originalmente).
Esto no es 100% satisfactorio para mí: tener que hacer la configuración tanto en la metaclase como en la clase de objeto parece que viola el principio DRY. Pero este último es solo un despachador de una sola línea; En general estoy de acuerdo con que exista, y probablemente podrías compactarlo con una lambda o algo así si realmente lo deseas.
No sé Python ... ¿es este el tipo de cosas que estás buscando? http://www.python.org/download/releases/2.2/descrintro/# property –
si estoy leyendo bien, puedes crear métodos para actuar como setter y getter (como en otros idiomas) para que puedas cargar el valor de la propiedad en el primer get ... lo cual creo es lo que querías? –
@ White Dragon. La función de propiedad que está buscando agrega propiedades a instancias de clase, no a las clases mismas. Estoy preguntando sobre 'Example.I' not' e.i'. –