7) Decorators Lesson

Python Decorators Step 5: Modify the Python Decorator

6 min to complete · By Martin Breuss

You've made it here, so it's finally time to get serious with your decorators! In this lesson, you'll create your first actual real-valid-now-it's-the-real-thing-really-decorator function. Wait a moment, what was the definition of a decorator again?

A function that takes another function and extends the behavior of the latter function without explicitly modifying it.

Build Your Final Python Decorator

You've already revisited the concepts of scopes, functions as objects, and arguments, and you've passed a function to a function in the previous lesson. Now, you'll build the final piece so that your decorator fits the definition shown above by extending the behavior of your initial function without explicitly modifying it:

def decorator_func(initial_func):
    def wrapper_func():
        print("the wrapper function picked some...")
        return initial_func()
    return wrapper_func

The only line of code you added in this example is a print() that displays half a sentence. However, you can see that you've added it inside the wrapper_func(), which means it'll be packaged up into the function object that your decorator returns.

Wrap A Function With A Decorator

Now that your functional decorator exists, you can apply it to a function. Just like in the example with your empty decorator before, you first define a new function. Then, you can decorate your brand new function with your decorator_func() by passing the function object to your decorator_func() as an argument:

def prettify():
    print("flowers for you")

decorated_pretty = decorator_func(prettify)

After you applied the decorator to prettify(), and created a new beast of a function object that you called decorated_pretty, and that extends the original behavior of prettify(), you can now call your new function:

decorated_pretty()

When calling your decorated function decorated_pretty(), you'll receive as an output first the message from the print() call inside your wrapper_func(), followed by the message from the print() call from your initial function, prettify().

Use Straightforward Syntax

In the above example, you needed to reassign the output of passing prettify to your decorator_func() to another variable, which you then called to get the output you were looking for.

Usually, you'll use decorators in a way that they would replace the initial function object. The only difference to the above would be that you're reassigning the output to the name of your initial function, thereby overwriting the initial function object:

def prettify():
    print("flowers for you")

prettify = decorator_func(prettify)
prettify()

As you saw further up, you could assign the newly wrapped function object to a new variable name, but for all practicality, you'll usually overwrite the initial function definition with its extended version.

Because this is such a common process when you're writing decorators, Python introduced a convenient syntax for achieving this task:

@decorator_func
def prettify():
    print("flowers for you")

prettify()

By placing the name of your decorator function prepended with an @ symbol in front of your function definition, you're automatically applying the decorator to that function. This means that the function object you're defining will be passed to the decorator and finally reassigned to the original name of your function, in this case, prettify().

However, you might wonder why wouldn't you just add the additional functionality directly into the new function you're defining. In the coming lesson, you'll see why the detour through writing a decorator can be useful.

Summary: Modify the Python Decorator

  • Changes in the wrapper function change the behavior of your initial function
  • A decorated function is created by passing your initial function to your decorator
  • The result inside your decorator is saved in a new function object
  • Usually, you want to overwrite the initial function with the newly decorated version of it
  • Python includes the @ decorator syntax
  • @ fixes the decorator to your function right when you define it