2

I have a following small Python program:

def wrap(func):
    print "before execution ..."
    a = func()
    print "after execution ..."
    return a


@wrap
def dosomething():
    print "doing something ..."

When I execute above script I should not get any output as I am not calling:

dosomething()

But when I execute this script I get the following output:

before execution ...
doing something ...
after execution ...

Please explain the reason for this behavior

Vishnu Upadhyay
  • 5,043
  • 1
  • 13
  • 24
openstk
  • 137
  • 9

5 Answers5

3

When you are using @ you are decorating the function you are annotating with another function. The decorator outer function is called when the decorator syntax is used - and that makes sense.

If you want to make a real decorator, you need to wrap the dosomething() call in another function in decorator body and return this new function - like that:

def wrap(func):
    print "before execution ..."
    def inner():
        a = func()
        return a
    print "after execution ..."
    return innner


@wrap
def dosomething():
    print "doing something ..."
Nebril
  • 3,153
  • 1
  • 33
  • 50
  • Thanks! When I execute your code I get: before execution ... after execution ... does that mean Python executes wrappers even if no one is calling them ? This point is still not clear to me – openstk Dec 09 '14 at 09:54
  • Yes! It's just syntactic sugar for the code that asafm posted. – Nebril Dec 09 '14 at 10:33
2

A decorator is just a callable that takes a function as an argument and returns a replacement function. We’ll start simply and work our way up to useful decorators.

The @ symbol applies a decorator to a function so it's equal to:

dosomething = wrap(dosomething) 

Which runs wrap. and prints the output.

Here's some info about decorators: https://wiki.python.org/moin/PythonDecorators

http://simeonfranklin.com/blog/2012/jul/1/python-decorators-in-12-steps/

asafm
  • 911
  • 6
  • 17
1

This is the decorator. read about it here.

what actually you are doing:-

def wrap(func):
    print "before execution ..."
    a = func()
    print "after execution ..."
    return a



def dosomething():   # if you remove this decorator symbol
    print "doing something ..."


wrap = wrap(dosomething) # this is what that `@wrap` is doing.
wrap()               

Here this is two step process:-

1:- @wrap pass the object of dosomething function to wrap function.

wrap = wrap(dosomething) # passing `dosomething` object to `wrap`

2:- now it call the wrap function

wrap()
Community
  • 1
  • 1
Vishnu Upadhyay
  • 5,043
  • 1
  • 13
  • 24
1

Decorators are executed in place of function definition. Upon importing a module (or running it) all top level statements are executed (classes, functions, etc.). If you had your decorated function inside another function, decorator inside it would only execute upon entering the function, like this:

def main():
    @wrap
    def dosomething():
       print "doing something ..."

In short... you shouldn't call your function inside a decorator, but rather return a wrapped function that will do what you want.

You want to define your decorator the following way to achieve the "expected" result:

def wrap(func):
    def wrapped(*args, **kwargs):
        print "before execution ..."
        func(*args, **kwargs)
        print "after execution ..."
    return wrapped
Rusty
  • 904
  • 4
  • 10
1

The Python interpreter executes all the code in the source file it's reading.

However, executing a def block doesn't execute the contained code, it just creates a function object, and that's why you're wondering why the def code is still running.

Here you have a decorator, which is translated to:

dosomething = wrap(dosomething)
dosomething()

Which runs the functions.

Maroun
  • 94,125
  • 30
  • 188
  • 241
  • @Shrirang This might be helpful http://simeonfranklin.com/blog/2012/jul/1/python-decorators-in-12-steps/ – Maroun Dec 09 '14 at 09:53