decorators question

K

king kikapu

Hi,

i am new to python and i have a question about how decorators are
working.
I have understand HOW they do their magic but i am trying to figure out

WHEN they do it...

I have the following simple example:

#-----------------------------------------
def author(author_name):
def decorator(func):
func.author_name = author_name
return func
return decorator

@author("some author")
def F():
pass

# print F.author_name
#-----------------------------------------


I am using Eclipse/PyDev and when i run this snippet from the PyDev
debugger,
i see that even though i do not call F() (or reference F.author_name),
the decorator and all this stuff is executed and updates F.autor_name
variable.

How is this thing really working ??
I mean, if we run this .py file (pythn test.py) from the command
prompt,
what the runtime will do, even if we do not have ane commands to
execute, only functions
as above ?

It will load all the module, all the functions and when it sees that
some function(s) are decorating, then it will start execute respectives
decorators ?
And this will do it for all decorated functions ?? Even if we do not
have any references to these functions ?

Shouldn't this code called when we actually DO call it ?


Thanks a lot for any enlightment on this,


objectref
 
F

Fredrik Lundh

king said:
It will load all the module, all the functions and when it sees that
some function(s) are decorating, then it will start execute respectives
decorators ?

@decorator
def func():
pass

is *exactly* the same thing as:

def func():
pass
func = decorator(func)
And this will do it for all decorated functions ?? Even if we do not
have any references to these functions ?

Python calls the decorator, not the decorated function.

additional reading:

http://www.python.org/doc/2.4.4/whatsnew/node6.html
http://www.python.org/dev/peps/pep-0318

and the relevant chapters in the tutorial and the language reference.

</F>
 
S

Soni Bergraj

Shouldn't this code called when we actually DO call it ?
Python statements are always executed to create the corresponding class
and function objects when a module is imported.

Cheers,
 
K

king kikapu

def func():
pass

is *exactly* the same thing as:

def func():
pass
func = decorator(func)

Yes, i know that but i thought that it is so when I call the function,
not when the runtime just loads the module...


Python calls the decorator, not the decorated function.


Hmmm...ok...it calls the decorator but when ?? It (the runtime) loads
the .py file and start to call every decorator
it finds on it, regardless of the existance of code that actually calls
the decorated functions ??
I understand thet Python does not call the decoratated functiond but it
ends up this way...

additional reading:

http://www.python.org/doc/2.4.4/whatsnew/node6.html
http://www.python.org/dev/peps/pep-0318

and the relevant chapters in the tutorial and the language reference.

I will have a lokk also thera, thanks!
 
S

Soni Bergraj

Hmmm...ok...it calls the decorator but when ?? It (the runtime) loads
the .py file and start to call every decorator
it finds on it, regardless of the existance of code that actually calls
the decorated functions ??
I understand thet Python does not call the decoratated functiond but it
ends up this way...
Python simply executes the module body when you import a module. class
and def statements result in binding of class and function objects to
the corresponding names. It's really that simple. Try the following to
get a deeper insight:

# file foobar.py

def bar(f):
return 'some text'

@def bar
def foo():
print "foo"


When you import this module module in an interactive python session you
will get he following.
Traceback (most recent call last):
'some text'

Hope that helps;)
 
F

Fredrik Lundh

king said:
Hmmm...ok...it calls the decorator but when ?? It (the runtime) loads
the .py file and start to call every decorator

you seem to be missing that the interpreter *always* executes the code
in a module to find out what it contains. "def" and "class" are exe-
cutable statement, not compiler directives. and the decorators are
simply called right after the corresponding "def" statement has been
executed.

</F>
 
S

Soni Bergraj

There was a copy-and-paste error with my last message. Better try this
for foobar.py:

def foo(f):
print "called foo"
return 'some text'
@foo
def bar():
print "called bar"
 
K

king kikapu

At first, i am coming from another (language) programming world (C#
mainly) and i hope you understand my wonders.

Ok then, you tell me that the interpreter always execute the code in a
module...If there are only def declarations in the module and no code
to invoke them it does not execute anything. It must have a body (a
call to a(some) method(s)) so it can execute something, right ??

In Soni's example (Soni thanks for the code), it indeed prints "called
foo" but if i remove the @foo statement,
as i see right now in the debugger, it does not execute anything.

I recap: if i put only functions declarations on a .py file, like
these:
def A(): print "a"
def B(): print "b"
def C(): print "c"

and run the program, nothing happens, nothing executed. I have to put a
statment like print A() or b() to cause code execution.

But if i simple declare a decorator for one function, like the one that
Soni gave me, then it caused the deco function to execute. Why is that
??
 
F

Fredrik Lundh

king said:
At first, i am coming from another (language) programming world (C#
mainly) and i hope you understand my wonders.

Ok then, you tell me that the interpreter always execute the code in a
module...If there are only def declarations in the module and no code
to invoke them it does not execute anything.

you're not listening. "def" is not a declaration, it's an executable
statement, just like "print" and ordinary assignments and "import" and
"class" and all the others.

the "def" statement itself is *executed* to define the function; it
takes the argument specification and the function code body, and creates
a new function object. the resulting object is assigned to an ordinary
variable.

the only thing that differs if you add a decorator to the mix is that
the function object is passed to the decorator function *before* it's
assigned to a variable.

</F>
 
C

Carsten Haese

I recap: if i put only functions declarations on a .py file, like
these:
def A(): print "a"
def B(): print "b"
def C(): print "c"

and run the program, nothing happens, nothing executed.

Nothing *visible* happens. The "def" statements *do* get executed.
Executing the statement

def A(): print "a"

does the following, roughly, modulo irrelevant implementation details:

* The function body gets compiled into byte code (but not executed).
* A callable object with the byte code for the compiled function body is
constructed.
* The thusly constructed callable object is bound to the name A in your
current namespace.

So, a lot of stuff happens when the interpreter executes a def
statement, but that stuff is not visible to you.

Hope this helps,

Carsten.
 
F

Fredrik Lundh

Carsten said:
* The function body gets compiled into byte code (but not executed).

careful: when you get as far as executing the "def" statement, the
function body has already been compiled. the byte code for the function
is stored as a module-level constant:
1 0 LOAD_CONST 0 (<code object func ...>)
3 MAKE_FUNCTION 0
6 STORE_NAME 0 (func)
....
* A callable object with the byte code for the compiled function body is
constructed.
* The thusly constructed callable object is bound to the name A in your
current namespace.

</F>
 
C

Carsten Haese

careful: when you get as far as executing the "def" statement, the
function body has already been compiled. the byte code for the function
is stored as a module-level constant:

You are, as always, correct, but I deliberately hid this detail inside
the "roughly, modulo irrelevant implementation details" disclaimer in an
attempt of causing the OP the smallest possible amount of confusion.

-Carsten
 
D

Duncan Booth

king kikapu said:
Hmmm...ok...it calls the decorator but when ?? It (the runtime) loads
the .py file and start to call every decorator
it finds on it, regardless of the existance of code that actually calls
the decorated functions ??
I understand thet Python does not call the decoratated functiond but it
ends up this way...

Try this code to help you understand what is going on:

----------- t.py ----------------
import inspect

def adecorator(f):
print "decorating", f.__name__, inspect.getargspec(f)
return f

def makeargument(n):
print "makeargument", n, "called"
return n

print "for loop coming up"
for i in range(3):
print "in for loop, iteration", i
@adecorator
def fn(x=makeargument(i)):
print "fn called, x=", x
print "end of iteration", i

print "now call fn"
fn()
print "done"
---------------------------------

Run it and the output shows you clearly when each element executes.

Note in particular that the def statement inside the loop executes every
time through the loop and each time it creates a new function (which
differs only in the default argument value), the default argument is
evaluated when the def executes, NOT when the function is called.
The decorator is called after the def executes and before the next
statement.
At the end of the for loop we are left only with the last definition of fn:
the others are overwritten during the loop.

The output looks like this:

C:\temp>t.py
for loop coming up
in for loop, iteration 0
makeargument 0 called
decorating fn (['x'], None, None, (0,))
end of iteration 0
in for loop, iteration 1
makeargument 1 called
decorating fn (['x'], None, None, (1,))
end of iteration 1
in for loop, iteration 2
makeargument 2 called
decorating fn (['x'], None, None, (2,))
end of iteration 2
now call fn
fn called, x= 2
done
 
K

king kikapu

you're not listening.

Be sure that i do...The fact that i come from another world does not
mean that i am not listening, just that i find as strange some (new)
things.
Thank you all guys, i know what is happening now...

Thanks again!

kikapu
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads


Members online

No members online now.

Forum statistics

Threads
474,432
Messages
2,571,680
Members
48,796
Latest member
Greg L.

Latest Threads

Top