Tengo algo parecido a lo siguiente. Básicamente, necesito acceder a la clase de un método de instancia desde un decorador utilizado en el método de instancia en su definición.
def decorator(view):
# do something that requires view's class
print view.im_class
return view
class ModelA(object):
@decorator
def a_method(self):
# do some stuff
pass
El código tal como está da:
AttributeError: el objeto 'función' no tiene atributo 'im_class'
Encontré preguntas / respuestas similares: el decorador de Python hace que la función olvide que pertenece a una clase y Obtener clase en el decorador de Python , pero se basan en una solución alternativa que captura la instancia en tiempo de ejecución al arrebatar el primer parámetro. En mi caso, llamaré al método en función de la información obtenida de su clase, por lo que no puedo esperar a que entre una llamada.
inspect.getmro(cls)
para procesar todas las clases base en el decorador de clases para admitir la herencia.inspect
que el rescate stackoverflow.com/a/1911287/202168Desde python 3.6 puede usar
object.__set_name__
para lograr esto de una manera muy simple. El documento establece que__set_name__
"se llama en el momento en que se crea el propietario de la clase propietaria ". Aquí hay un ejemplo:Tenga en cuenta que se llama en el momento de la creación de la clase:
Si desea saber más sobre cómo se crean las clases y, en particular, exactamente cuándo
__set_name__
se llama, puede consultar la documentación sobre "Creación del objeto de clase" .fuente
@class_decorator('test', foo='bar')
def decorator(*args, **kwds): class Descriptor: ...; return Descriptor
__set_name__
aunque he estado usando Python 3.6+ durante mucho tiempo.hello
no es un método, sino un objeto de tipoclass_decorator
.if TYPE_CHECKING
para definirclass_decorator
como un decorador normal que devuelve el tipo correcto.Como han señalado otros, la clase no se ha creado en el momento en que se llama al decorador. Sin embargo , es posible anotar el objeto de función con los parámetros del decorador y luego volver a decorar la función en el
__new__
método de la metaclase . Deberá acceder al__dict__
atributo de la función directamente, ya que al menos para mí,func.foo = 1
resultó en un AttributeError.fuente
setattr
debe usarse en lugar de acceder__dict__
Como sugiere Mark:
Este código muestra cómo puede funcionar esto usando el posprocesamiento automático:
La salida rinde:
Tenga en cuenta que en este ejemplo:
Espero que esto ayude
fuente
Como indicó Ants, no puede obtener una referencia a la clase desde dentro de la clase. Sin embargo, si está interesado en distinguir entre diferentes clases (sin manipular el objeto de tipo de clase real), puede pasar una cadena para cada clase. También puede pasar cualquier otro parámetro que desee al decorador utilizando decoradores de estilo de clase.
Huellas dactilares:
Además, vea la página de Bruce Eckel sobre decoradores.
fuente
@decorator('Bar')
, a diferencia de@Decorator('Bar')
.Lo que hace flask-classy es crear un caché temporal que almacena en el método, luego usa algo más (el hecho de que Flask registrará las clases usando un
register
método de clase) para realmente envolver el método.Puede reutilizar este patrón, esta vez usando una metaclase para que pueda ajustar el método en el momento de la importación.
En la clase real (puede hacer lo mismo usando una metaclase):
Fuente: https://github.com/apiguy/flask-classy/blob/master/flask_classy.py
fuente
El problema es que cuando se llama al decorador, la clase aún no existe. Prueba esto:
Este programa generará:
Como puede ver, tendrá que encontrar una forma diferente de hacer lo que quiera.
fuente
He aquí un ejemplo sencillo:
La salida es:
fuente
Esta es una vieja pregunta pero se encontró con venusiana. http://venusian.readthedocs.org/en/latest/
Parece tener la capacidad de decorar métodos y darle acceso tanto a la clase como al método mientras lo hace. Tenga en cuenta que llamar
setattr(ob, wrapped.__name__, decorated)
no es la forma típica de usar venusian y en cierto modo frustra el propósito.De cualquier manera ... el siguiente ejemplo está completo y debería ejecutarse.
fuente
La función no sabe si es un método en el punto de definición, cuando se ejecuta el código del decorador. Solo cuando se accede a través del identificador de clase / instancia, puede conocer su clase / instancia. Para superar esta limitación, puede decorar por objeto descriptor para retrasar el código de decoración real hasta la hora de acceso / llamada:
Esto le permite decorar métodos individuales (estáticos | clase):
Ahora puedes usar el código del decorador para la introspección ...
... y para cambiar el comportamiento de la función:
fuente
</sigh>
Como han señalado otras respuestas, el decorador es algo funcional, no puede acceder a la clase a la que pertenece este método ya que la clase aún no se ha creado. Sin embargo, está totalmente bien usar un decorador para "marcar" la función y luego usar técnicas de metaclase para tratar el método más tarde, porque en la
__new__
etapa, la clase ha sido creada por su metaclase.He aquí un ejemplo sencillo:
Usamos
@field
para marcar el método como un campo especial y tratarlo en la metaclase.fuente
if inspect.isfunction(v) and getattr(k, "is_field", False):
debería sergetattr(v, "is_field", False)
en su lugar.Tendrá acceso a la clase del objeto en el que se llama al método en el método decorado que debe devolver su decorador. Al igual que:
Usando su clase ModelA, esto es lo que hace:
fuente
Solo quiero agregar mi ejemplo, ya que tiene todas las cosas que se me ocurren para acceder a la clase desde el método decorado. Utiliza un descriptor como sugiere @tyrion. El decorador puede tomar argumentos y pasarlos al descriptor. Puede tratar tanto con un método en una clase como con una función sin una clase.
fuente