class Deco: def __init__(self, name): self.name = name def __call__(self, test_class): def inner_func(whatisit): return whatisit test_class.method = inner_func return test_class class TestClass: def __init__(self, name): self.name = name @Deco('deco') class TestClassWrapped: def __init__(self, name): self.name = name test = TestClass('test') test = Deco('deco')(test) test_wrapped = TestClassWrapped('test') print(test.method('whatisit')) >> whatisist print(test_wrapped == test_wrapped.method()) >> True
test_wrapped.method return different results ?
It seems that the first argument in
self, while it isn’t for
test.method. Why does it differ from one to the other?
Walking through your code step-by-step:
You create a regular
You manually call
Decoand provide it with
test, with the line
test = Deco('deco')(test).
This makes your code go through the
__call__function, which modifies the passed class
testto set its
methodattribute to the nested function. It then returns it, and so
testnow contains a successfully modified
test.method('whatisit')will successfully return
'whatisit'. Importantly, you’re NOT accessing a method here : you’re accessing a FUNCTION through an ATTRIBUTE.
selfis passed to every method of classes in Python, but since this isn’t a method, it doesn’t come into play here. Try printing
type(test.method), you’ll see
<class 'function'>and not
<class 'method'>. Importantly, you’ve passed an INSTANCE of a
TestClass, not the class definition itself : and only this instance named
testhas had its
You then create a
test_wrapped. Upon creating it, it enters the
__call__once more, passing it
test_classparameter. Importantly, you’ve passed a DEFINITION of the
TestWrappedClass, not an instance of it. Setting
methodhere will modify it for every instance of
TestWrappedClassyou’ll later create, and can even be accessed without instantiating anything. Try calling
TestClassWrapped.method("abc"): it will print
abcwithout instantiating a
TestClassWrappedat all. Interestingly, when set in this way, it’s not set as an attribute but as a method! Try printing
type(test_wrapped.method). This is what I believe to be the source of confusion.
In the case of
print(test_wrapped.method()), you have to remember that every method of instantiated classes take
selfas their first parameter. This means that
self: hence why
test_wrapped == test_wrapped.method(). Note that this doesn’t apply to methods called from a class definition, like I’ve shown earlier.
TestClassWrapped.method("abc")HAS to take a parameter of some sort (like
abc), else it will complain it’s lacking an argument.
So this is why
'whatisit' and doesn’t take
self as parameter, and why
test_wrapped.method() does return