Tengo una clase con dos métodos de clase (usando la función classmethod ()) para obtener y establecer lo que es esencialmente una variable estática. Intenté usar la función property () con estos, pero resulta en un error. Pude reproducir el error con lo siguiente en el intérprete:
class Foo(object):
_var = 5
@classmethod
def getvar(cls):
return cls._var
@classmethod
def setvar(cls, value):
cls._var = value
var = property(getvar, setvar)
Puedo demostrar los métodos de clase, pero no funcionan como propiedades:
>>> f = Foo()
>>> f.getvar()
5
>>> f.setvar(4)
>>> f.getvar()
4
>>> f.var
Traceback (most recent call last):
File "<stdin>", line 1, in ?
TypeError: 'classmethod' object is not callable
>>> f.var=5
Traceback (most recent call last):
File "<stdin>", line 1, in ?
TypeError: 'classmethod' object is not callable
¿Es posible usar la función property () con funciones decoradas con método de clase?
class Foo(metaclass=...)
sintaxis.Al leer las notas de la versión de Python 2.2 , encuentro lo siguiente.
NOTA: El siguiente método en realidad no funciona para setters, solo getters.
Por lo tanto, creo que la solución prescrita es crear una ClassProperty como una subclase de propiedad.
Sin embargo, los setters en realidad no funcionan:
foo._var
no ha cambiado, simplemente ha sobrescrito la propiedad con un nuevo valor.También puedes usar
ClassProperty
como decorador:fuente
self.fget(owner)
y elimina la necesidad de tener que usar un@classmethod
en absoluto aquí. (eso es loclassmethod
que se traduce.__get__(instance, owner)(*args, **kwargs)
enfunction(owner, *args, **kwargs)
llamadas a través de un intermediario; las propiedades no necesitan el intermediario)foo.var = 3
asignación en realidad no pasa por la propiedad , y en su lugar simplemente ha reemplazado el objeto de propiedadfoo
con un número entero. Si agregaassert isinstance(foo.__dict__['var'], ClassProperty)
llamadas entre sus afirmaciones, verá que falla después de quefoo.var = 3
se ejecuta.instance.attr
,instance.attr = value
ydel instance.attr
se unen todos en el descriptor encontradotype(instance)
, pero al mismo tiempoclassobj.attr
se une,classobj.attr = value
ydel classobj.attr
qué no y en lugar de sustituir o eliminar el objeto descriptor de sí mismo). Necesita una metaclase para admitir la configuración y eliminación (haciendo que el objeto de clase sea la instancia y la metaclase el tipo).Espero que este simple
@classproperty
decorador de solo lectura ayude a alguien que busque propiedades de clase.fuente
class D(C): x = 2; assert D.x == 2
.format
como"{x}".format(**dict(self.__class__.__dict__, **self.__dict__))
:(x
accesos10
. Me gusta este enfoque porque es ordenado y simple pero suena como un antipatrón__set__
que genere unValueError
para evitar la anulación.No.
Sin embargo, un método de clase es simplemente un método enlazado (una función parcial) en una clase accesible desde instancias de esa clase.
Dado que la instancia es una función de la clase y puede derivar la clase de la instancia, puede obtener el comportamiento deseado que desee de una propiedad de clase con
property
:Este código se puede usar para probar, debe pasar sin generar ningún error:
Y tenga en cuenta que no necesitábamos metaclases en absoluto, y de todos modos no accede directamente a una metaclase a través de las instancias de sus clases.
escribiendo un
@classproperty
decoradorEn realidad, puede crear un
classproperty
decorador en solo unas pocas líneas de código subclasificandoproperty
(está implementado en C, pero puede ver Python equivalente aquí ):Luego trate al decorador como si fuera un método de clase combinado con una propiedad:
Y este código debería funcionar sin errores:
Pero no estoy seguro de lo bien aconsejado que sería. Un viejo artículo de la lista de correo sugiere que no debería funcionar.
Conseguir que la propiedad funcione en la clase:
La desventaja de lo anterior es que la "propiedad de clase" no es accesible desde la clase, porque simplemente sobrescribiría el descriptor de datos de la clase
__dict__
.Sin embargo, podemos anular esto con una propiedad definida en la metaclase
__dict__
. Por ejemplo:Y luego una instancia de clase de la metaclase podría tener una propiedad que acceda a la propiedad de la clase utilizando el principio ya demostrado en las secciones anteriores:
Y ahora vemos tanto la instancia
y la clase
tener acceso a la propiedad de la clase.
fuente
Python 3!
Antigua pregunta, muchas vistas, que necesitan urgentemente una forma única de Python 3.
Afortunadamente, es fácil con el
metaclass
kwarg:Luego,
>>> Foo.var
fuente
Foo
es una instancia de su metaclase, y@property
puede usarse para sus métodos de la misma manera que para las instancias deFoo
.Foo.__new__
. Aunque en ese momento puede valer la pena usar getattribute en su lugar, o cuestionarse si pretender que existe una característica del lenguaje es realmente el enfoque que desea adoptar.No hay una forma razonable de hacer que este sistema de "propiedad de clase" funcione en Python.
Aquí hay una forma irrazonable de hacerlo funcionar. Ciertamente puedes hacerlo más fluido con cantidades crecientes de metaclases mágicas.
El nudo del problema es que las propiedades son lo que Python llama "descriptores". No hay una manera corta y fácil de explicar cómo funciona este tipo de metaprogramación, por lo que debo señalarle el descriptor .
Solo necesita comprender este tipo de cosas si está implementando un marco bastante avanzado. Como una persistencia de objetos transparentes o un sistema RPC, o un tipo de lenguaje específico de dominio.
Sin embargo, en un comentario a una respuesta anterior, usted dice que
Me parece que lo que realmente quieres es un patrón de diseño Observer .
fuente
Establecerlo solo en la metaclase no ayuda si desea acceder a la propiedad de la clase a través de un objeto instanciado, en este caso también necesita instalar una propiedad normal en el objeto (que se envía a la propiedad de la clase). Creo que lo siguiente es un poco más claro:
fuente
La mitad de una solución, __set__ en la clase aún no funciona. La solución es una clase de propiedad personalizada que implementa tanto una propiedad como un método estático
fuente
¿Tiene acceso a al menos una instancia de la clase? Entonces puedo pensar en una forma de hacerlo:
fuente
Intente esto, hace el trabajo sin tener que cambiar / agregar mucho código existente.
La
property
función necesita doscallable
argumentos. darles envoltorios lambda (que pasa la instancia como su primer argumento) y todo está bien.fuente
Aquí hay una solución que debería funcionar para el acceso a través de la clase y el acceso a través de una instancia que utiliza una metaclase.
Esto también funciona con un setter definido en la metaclase.
fuente
Después de buscar en diferentes lugares, encontré un método para definir una propiedad de clase válida con Python 2 y 3.
Espero que esto pueda ayudar a alguien :)
fuente
Aquí está mi sugerencia. No uses métodos de clase.
Seriamente.
¿Cuál es la razón para usar métodos de clase en este caso? ¿Por qué no tener un objeto ordinario de una clase ordinaria?
Si simplemente desea cambiar el valor, una propiedad no es realmente muy útil, ¿verdad? Simplemente configure el valor del atributo y termine con él.
Una propiedad solo debe usarse si hay algo que ocultar, algo que podría cambiar en una implementación futura.
Tal vez su ejemplo está muy despojado, y hay algunos cálculos infernales que ha dejado. Pero no parece que la propiedad agregue un valor significativo.
Las técnicas de "privacidad" influenciadas por Java (en Python, nombres de atributos que comienzan con _) no son realmente muy útiles. Privado de quien? El punto de privado es un poco nebuloso cuando tienes la fuente (como lo haces en Python).
Los captadores y establecedores de estilo EJB influenciados por Java (a menudo hechos como propiedades en Python) están ahí para facilitar la introspección primitiva de Java, así como para pasar la lista con el compilador de lenguaje estático. Todos esos captadores y establecedores no son tan útiles en Python.
fuente