Your 2nd code block can "get the job done" each time it is evaluated. What if you need to do this many times? Each time you must evaluate the expression decor(some_function)
, even if the decorated function, some_function
, happens to be the same thing. What if the context of its evaluation isn't fully in your control?
With the 1st approach, you basically wrap the decorated function in the same thunk that can be evaluated later. You than call the same thunk each time you need it called. You can even delegate the call to someone else.
Your decorator example is trivial. When the code gets more complex, Python's ability to return a function as first-class object is a boon. An example would be that an API expects a callback:
def frob(some, args, callback=your_function):
Now, you've written your callback and you discover that the performance can be boosted by memoization. With the decorator pattern you can do things like
my_function_memoized = memoize(my_function, *even_more_parameters_controlling_the_memoization_behavior) # returns decorate function
... ...
frob(some, args, callback=my_function_memoized)
That is to say, the decorated thunk can be used just in the place of my_function
. This happens a lot in Python, because Python makes it very easy to pass callables around.