Reputation: 189
For module-level functions, this code holds:
def dec(f):
def wrap(*args, **kwargs):
f(*args, **kwargs)
return wrap
@dec
def foo(arg1):
pass
When decorating methods however, all of a sudden you'll have to have one parameter to catch the instance.
def dec(f):
def wrap(self, *args, **kwargs):
f(self, *args, **kwargs)
return wrap
class Test:
def __init__(self):
pass
@dec
def foo(self, arg1):
pass
Why is that the case? What's so special about self
that *args
isn't able to catch it? After all isn't it just another positional argument?
Also, how is it(self
) passed into the inner wrap
function?
For the first case, it's simply equivalent to foo = dec(foo)
. From what I've learned with closures, before foo
is passed as an argument to the decorator. It creates an enclosure with __closure__
, so it's able to retain whatever arguments were passed to foo
.
Why is it that when it comes to methods then, apparently self
doesn't seem to be part of the __closure__
?
Upvotes: 4
Views: 94
Reputation: 500367
Why is that the case? What's so special about
self
that*args
isn't able to catch it?
This question is based on a premise that's flawed. As a matter of fact, *args
can include self
, both with and without decorators. This is illustrated by the following two examples.
Without decorators:
class Test(object):
def foo(self, *args):
return (self,) + args
def bar(*args): # for the purposes of illustration
return args
t = Test()
print(t.foo(42))
print(t.bar(42))
With decorators:
def dec(f):
def wrap(*args, **kwargs):
return f(*args, **kwargs)
return wrap
class Test(object):
@dec
def foo(self, arg1):
return (self, arg1)
t = Test()
print(t.foo(42))
Upvotes: 3
Reputation: 87
I think it is best stated by the creator of Python himself:
http://neopythonic.blogspot.com/2008/10/why-explicit-self-has-to-stay.html
The main two points are:
There's a pretty good argument to make that requiring explicit 'self' in the parameter list reinforces the theoretical equivalency between these two ways of calling a method.
and
Another argument for keeping explicit 'self' in the parameter list is the ability to dynamically modify a class by poking a function into it, which creates a corresponding method.
Upvotes: 0