Reputation: 13
Recently I'm learning Python decorator and the use of functools.wraps
.
def a():
def b():
def c():
print('hello')
return c
return b
print a.__name__
#output:a
I understand why the output is a.But I don't know how __name__
change in the following code.
def log(text):
def decorator(func):
def wrapper(*args, **kw):
print('%s %s():' % (text, func.__name__))
return func(*args, **kw)
return wrapper
return decorator
@log('...')
def simple():
print('*' * 20)
print simple.__name__
#output:wrapper
Why the output is 'wrapper' rather than 'decorator' or 'log'?
Upvotes: 1
Views: 2362
Reputation: 23213
Some basics:
@decorator
def f():
pass
is equivalent to:
def f():
pass
f = decorator(f)
Decorator with args:
@decorator(*args, **kwargs)
def f():
pass
is equivalent to:
def f():
pass
decorator_instance = decorator(*args, **kwargs)
f = decorator_instance(f)
With knowing so, we may rewrite your example to:
def simple():
print('*' * 20)
log_instance = log('...')
simple = log_instance(simple)
Let's analyze what happens in last two lines:
log_instance
is a decorator
function, and text variable within it is equal to '...'decorator
(regardless of text
value) returns function named wrapper, simple
is replaced with function named wrapper
Upvotes: 2
Reputation: 27403
@log('...')
def simple(...
is equivalent to
def simple(...
simple = log('...')(simple)
so log
is actually called, returning decorator
, which is called with simple
as argument which is then replaced by decorator
's return value, which is the function wrapper
, thus its __name__
is wrapper
.
Upvotes: 0
Reputation: 22979
The point of decorators is to replace a function or class with what is returned by the decorator, when called with that function/class as argument. Decorators with arguments are a bit more convoluted, as you first call the outer method (log
) to obtain a "parameterized" decorator (decorator
), then you call that one and obtain the final function (wrapper
), which will replace the decorated function (simple
).
So, to give it some structure,
log
with '...'
as argument and obtain decorator
decorator
with simple
as argument and obtain wrapper
simple
with wrapper
Upvotes: 0