In Python 3 there are no bound methods (known from Python 2), but we always create functions.
After declaring a function inside a class, something is creating automatic Pythons descriptor, which will append self
as first argument, when this function will be called as instance method.
So basically, following code:
def funcdecorator(func):
def f(*args, **kwargs):
print('funcdecorator:', args, kwargs)
return f
class X:
@funcdecorator
def f(self):
pass
X().f()
will output:
funcdecorator: (<__main__.X object at ...>,) {}
(the first argument is passed as self
)
but with following code:
def classdecorator(func):
class C:
def __call__(*args, **kwargs):
print('classdecorator:', args, kwargs)
return C()
class X:
@classdecorator
def f(self):
pass
X().f()
we get:
classdecorator: (<__main__.C object at 0x1bbea10>,) {}
which is logical.
But, is it possible to return from decorator an class instance and mimic it is a function, so when 'calling' it, the first passed argument will be an instance of X
, not an instance of C
?
The class C
needs to be a descriptor, i.e. implement __get__
. Then, X().f()
will first call the descriptor's __get__
, passing the X instance and a reference to X. Whatever __get__
returns will then see __call__
invoked.