Search code examples
pythonpython-decorators

why python decorator result like this..?


these days, i study python decorator,, and my question code is this.

import functools
def my_decorator(func):
    @functools.wraps(func)
    def wrapper():
        print("Something is happening before the function is called.")
        func()
        print("Something is happening after the function is called.")
    return wrapper

@my_decorator
def say_hello():
    print("hello!")

ret = my_decorator(say_hello)
ret()

actually, i expect this result

Something is happening before the function is called.
hello!
Something is happening after the function is called.

but real output is like this.

Something is happening before the function is called.
Something is happening before the function is called.
hello!
Something is happening after the function is called.
Something is happening after the function is called.

can someone tell me why result like this?


Solution

  • You have decorated your function say_hello twice.

    Generally, in examples of decorators, the function wrapper is explicitly called i.e:

    def outer(f):
      def wrapper():
         f()
      return wrapper
    
    def stuff():
      print('hello from stuff')
    
    new_stuff = outer(stuff)
    new_stuff()
    

    Which will give 'hello from stuff' outputted to the console, as new_stuff is storing the function object wrapper, returned from outer. However, using the @decorator syntactic sugar automatically performs the first call i.e outer(stuff). Thus, the example above is comparable to:

    def outer(f):
      def wrapper():
        f()
      return wrapper
    
    @outer
    def stuff():
      print('hello from stuff')
    

    Thus, in your example, simply calling say_hello (say_hello()) will correctly output

    Something is happening before the function is called.
    hello!
    Something is happening after the function is called.