-1

I'm trying to understand Python decorators and have written this code:

def hello_world(fn):
    print('hello world')
    fn()
    pass

@hello_world
def decorate():
    print('hello decoatrion')
    return

decorate()

I was aiming to print 'hello world' before 'hello decoration', but the output is the following:

hello world
hello decoatrion
Traceback (most recent call last):
  File "test_decortor.py", line 11, in <module>
    decorate()
TypeError: 'NoneType' object is not callable
martineau
  • 119,623
  • 25
  • 170
  • 301
abdo_mah90
  • 83
  • 1
  • 7
  • OK, so what's your question? – melpomene Jul 23 '16 at 13:06
  • Possible duplicate of [How can I make a chain of function decorators in Python?](http://stackoverflow.com/questions/739654/how-can-i-make-a-chain-of-function-decorators-in-python) – GingerPlusPlus Jul 23 '16 at 13:13
  • Your decorator is returning `None`, not the decorated function. Check out [these examples](https://docs.python.org/3/whatsnew/2.4.html#pep-318-decorators-for-functions-and-methods), as well as [PEP 318 - Decorators for Functions, Methods and Classes](https://www.python.org/dev/peps/pep-0318/) itself. – martineau Jul 23 '16 at 13:19

2 Answers2

3

The decorator must return the decorated function. You probably wanted something along these lines:

def hello_world(fn):
    def inner():
        print('hello world')
        fn()
    return inner

@hello_world
def decorate():
    print('hello decoatrion')
    return

decorate()
#output: hello world
#        hello decoatrion
Graham
  • 7,431
  • 18
  • 59
  • 84
Aran-Fey
  • 39,665
  • 11
  • 104
  • 149
3

Decorator syntax is shorthand for

decorated = decorate(decorated)

So if you have:

def hello_world(fn):
    print('hello world')
    fn()
    pass

def decorate():
    print('hello decoatrion')
    return

decorate = hello_world(decorate)

You should see what the problem is (also note that pass does nothing here).

def hello_world(fn):
    def says_hello():
        print('hello world')
        return fn()
    return says_hello

def decorate():
    print('hello decoration')

decorate = hello_world(decorate)

will do what you want. Or you could write it:

@hello_world
def decorate():
    print('hello decoration')
Wayne Werner
  • 49,299
  • 29
  • 200
  • 290