Example code:
# -*- coding: utf-8 -*-
from functools import wraps
class MyClass(object):
def __init__(self):
pass
#decorator inside class
def call(f):
@wraps(f)
def wrapper(*args):
print 'Wrapper: ', args
return wrapper
#decorated 'method' without self
@call
def myfunc(a):
pass
c = MyClass()
c.myfunc(1)
Returns:
Wrapper: (<test3.MyClass object at 0xb788a34c>, 1)
Is this normal? Can someone explain?
If this is a feature I would use it in my library.
This is perfectly normal.
The function
myfuncis replacecd by an instance ofwrapper. The signature ofwrapperis(*args). because it is a bound method, the first argument is the instance ofMyClasswhich is printed out after the string `Wrapper: ‘.What’s confusing you?
It’s worth noting that if you use
callas a decorator from outside ofMyClass, it will generate aTypeError. One way around this is to apply thestaticmethoddecorator to it but then you can’t call it during class construction.It’s a little bit hacky but I address how to have it both ways here.
update after comment
it gets the instance as the first argument regardless of if you type
selfin the parameter list because after the class is created, and an instance instantiated, it is a bound method. when you call it in the formit expands to
but note that you are calling it on an instance! This will automatically expand to a call of the form
This is how methods work. But you only defined
callto take one argument so this raises aTypeError.As for calling it during class construction, it works fine. but the function that it returns gets passed an instance of
MyClasswhen it is called for the same reason that I explained above. Specifically, whatever arguments you explicity pass to it come after the implicit and automatic placement of the instance that it is called upon at the front of the argument list.