tengo este codigo:
from typing import Callable, Any class Test(classmethod): def __init__(self, f: Callable[..., Any]): super().__init__(f) def __get__(self,*args,**kwargs): print(args) # why out put is (None, <class '__main__.A'>) where form none why no parameter 123 # where was it called return super().__get__(*args,**kwargs) class A: @Test def b(cls,v_b): print(cls,v_b) Ab(123) ¿Por qué la salida es (None, <class '__main__.A'>) ? ¿Dónde se formó None y por qué no es el parámetro 123, que es el valor con el que lo llamé?
El método __get__ se llama cuando el método b se recupera de la clase A No tiene nada que ver con el llamado real de b .
Para ilustrar esto, separe el acceso a b de la llamada real de b :
print("Getting a reference to method Ab") method = Ab print("I have a reference to the method now. Let's call it.") method()Esto da como resultado esta salida:
Getting a reference to method Ab (None, <class '__main__.A'>) I have a reference to the method now. Let's call it. <class '__main__.A'> 123 Como ve, es normal que la salida en __get__ no muestre nada sobre el argumento con el que llama a b , porque aún no ha realizado la llamada.
La salida None, <class '__main__.A'> está en línea con la documentación de Python en __get__ :
object.__get__(self, instance, owner=None)Llamado para obtener el atributo de la clase propietaria (acceso a atributos de clase) o de una instancia de esa clase (acceso a atributos de instancia). El argumento de propietario opcional es la clase de propietario, mientras que la instancia es la instancia a través de la cual se accedió al atributo, o
Nonecuando se accede al atributo a través del propietario .
En su caso, lo está utilizando para acceder a un atributo ( b ) de una clase ( A ), no de una instancia de A , por lo que explica que el argumento de la instance es None y el argumento del owner es su clase A
La segunda salida, hecha con print(cls,v_b) , imprimirá <class '__main__.A'> para cls , porque eso es lo que sucede cuando llamas a métodos de clase (a diferencia de los métodos de instancia ). Nuevamente, de la documentación :
Cuando una referencia de atributo de clase (para la clase
C, digamos) produce un objeto de método de clase, se transforma en un objeto de método de instancia cuyo atributo__self__esC
Su caso se describe aquí, donde A es la clase, por lo que el primer parámetro (al que llamó cls ) obtendrá el valor A .
Puede aplicar varios decoradores en la misma función, por ejemplo,
In [4]: def test_deco(func): ...: def wrapper(cls, *args, **kwds): ...: print("cls is", cls) ...: print("That's where 123 should appear>>>", args, kwds) ...: return func(cls, *args, **kwds) ...: ...: return wrapper ...: ...: ...: class A: ...: @classmethod ...: @test_deco ...: def b(cls, v_b): ...: print("That's where 123 will appear as well>>>", v_b) ...: ...: ...: Ab(123) cls is <class '__main__.A'> That's where 123 should appear>>> (123,) {} That's where 123 will appear as well>>> 123 In [5]:Es demasiado problema usar dos a la vez. Solo quiero usar uno igual.
Es posible definir un decorador aplicando un par de otros decoradores:
def my_super_decorator_doing_everything_at_once(func): return classmethod(my_small_decorator_doing_almost_everything(func))Eso funciona porque la notación de decoradores
@g @f def x(): ...es una manera legible de decir
def x(): ... x = g(f(x))