vks vks - 27 days ago 15
Python Question

Decorators not changing dir()

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

Answer

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. It is, after all, a different object.

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):

references in the Python Tutor visualisation

Comments