Python decorators when used without
@functools.wraps(function)
changes the original function's __doc__
,__name__
,help
which is understandable as decorator is simply
fun=decorate(fun)
but why doesnt it change dir(fun) for that function ? shouldn't it change as well ?
For example:
def wow(func):
def __wow():
return func()
return __wow
@wow
def fun():
print "yes"
fun.b=1
print fun.__name__
print dir(fun)
The output is
__wow => name of decorator
[... '__sizeof__', '__str__', '__subclasshook__', 'b', 'func_closure', ...]
^^
If you see here,when we print name
it is of decorator
but when we print dir
its of fun
as b
is in there.So why is b
there?Shouldnt it be dir(decorator)
as fun.name gives that of decorator
You seem to miss a crucial step in decorators. You do grasp that using a decorator @decorate
on a function fun
does this:
fun = decorate(fun)
but then don't follow through. fun
is now bound to the return value of the decorator.
You said:
Python decorators [...] changes the original function's
__doc__
,__name__
,help
This is not true. The original, undecorated function is unchanged. It still has the same __doc__
, the same __name__
, etc. The returned object from the decorator, now bound to the original name, however, may well have a different name or docstring. After all, it may well be a different object altogether.
In your sample, you returned __wow
from the decorator, so Python assigned that object to fun
. fun
is just a name here, one that references the result of the decorator. The original fun
function is no longer available via that name; at no point are you inspecting the original, undecorated function here.
So using dir()
on the name fun
means it is applied to whatever fun
is bound to now, and that is the __wow
function produced by the decorator. Setting attributes on fun
, sets attributes on that same function object. All attributes reflect this.
You may find it helpful to step through what Python does and visualise those steps. See this Python Tutor visualisation; it shows you what fun
references in the end (and where the original function object ended up):