6
I’m trying to implement a class that’s a method Decorator python. The idea is to apply it to the methods of other classes. However, it is getting lost in the reference self
of the annotated class method.
I did the following MCVE to demonstrate the problem:
import traceback
class Decorator:
def __init__(self, wrapped):
self.__wrapped = wrapped
def __call__(self, *args, **kwargs):
print(f"PARÂMETROS: args = {args}, kwargs = {kwargs}")
return self.__wrapped(*args, **kwargs)
class Teste:
def __init__(self):
self.__x = 123
@Decorator
def foo(self):
return self.__x
x = Teste()
print("\nInvocando método de instância como se fosse estático.")
try:
print(Teste.foo(x))
print("Funcionou!")
except:
traceback.print_exc()
print("\nInvocando método de instância diretamente.")
try:
print(x.foo())
print("Funcionou!")
except:
traceback.print_exc()
In the code above, I created the class Decorator
the instances of which must be applied to methods of other classes such as method decorators. The class Teste
is the method containing the foo
decorated. The subsequent code attempts to invoke the method foo
of Teste
in two different ways (as if it were a static method and in the usual way as an instance method).
That is the result:
Invocando método de instância como se fosse estático.
PARÂMETROS: args = (<__main__.Teste object at 0x02BE0E90>,), kwargs = {}
123
Funcionou!
Invocando método de instância diretamente.
PARÂMETROS: args = (), kwargs = {}
Traceback (most recent call last):
File "mcve.py", line 30, in <module>
print(x.foo())
File "mcve.py", line 9, in __call__
return self.__wrapped(*args, **kwargs)
TypeError: foo() missing 1 required positional argument: 'self'
The result demonstrates that invoking Teste.foo(x)
works, but invoke x.foo()
does not work. I would like instance methods to be called as such, regardless of the fact that I have applied a method Decorator arbitrary in it. Note that when the method is called such as an instance method, the instance of Teste
is not even in the args
nor in the kwargs
.
I also tried it from here, but again it didn’t work:
class Decorator:
def __init__(self, wrapped):
self.__wrapped = wrapped
def __call__(*args, **kwargs):
print(f"PARÂMETROS: args = {args}, kwargs = {kwargs}")
return args[0].__wrapped(*args, **kwargs)
So I ask:
How can I make a method Decorator that is a form class that a call
x.foo()
work?Or otherwise, how can I "fish" the reference to instance of the decorated method (the
self
offoo
) instead of taking theself
of own Decorator?
Addendum
Imagining that the class Decorator
be it so:
class Decorator:
def __init__(self, wrapped):
self.__wrapped = wrapped
def __call__(self, *args, **kwargs):
print(f"PARÂMETROS: args = {args}, kwargs = {kwargs}")
return self.__wrapped(*args, **kwargs)
def bar(self):
return 456
The idea is that print(x.foo.bar)
also prints 456.
You may be able to implement different solutions using the method
__new__
or descriptors, but need to analyze more calmly in a time of less fatigue.– Woss
I will test this tomorrow calmly. Anyway, your answer seems very good, already has my +1.
– Victor Stafusa
Well, I ran some tests, and your solution solves what I put into the mess. However, when I was reducing my original problem to a MCVE, I cut the other methods of the Decorator and with the proposed solution, they become inaccessible. The reason Decorator was returned instead of a closure was so that such methods would be available. Do you know any solution to this case?
– Victor Stafusa
@Victorstafusa accessible from where? If you go from inside the decorator, even inside the closure Voce can access them. I even put as comment in the code this. Gave some error when trying to play?
– Woss
Externally accessible as
x.foo.bar
. I edited the question.– Victor Stafusa
His answer helped me to solve the problem, but did not completely solve it. After breaking my head for a few days, I arrived at the solution of the answer I posted here. I thank you very much for the help.
– Victor Stafusa