Skip to main content

Python Decorators

With a decorator, you can give a function extra behavior and leave its code untouched.

A decorator is itself a function. It receives a function as input and gives back a new one.


Basic Decorator

First define the decorator, then write @decorator_name on the line above the function you want to apply it to.

In the example, the @changecase line sitting right above myfunction "decorates" it with changecase.

So changecase is the decorator.

And myfunction is the function being decorated.

Example

This decorator converts whatever the decorated function returns to upper case.

Prompt
Create a decorator changecase that converts a function's return value to uppercase. Apply it to a function that returns "Hello Sally" and print the result.
Output: complete Python program

Multiple Decorator Calls

One decorator can be reused as often as you like. Simply put it above each function that needs it.

Example

The same @changecase decorator applied to two functions:

Prompt
Create a decorator changecase that uppercases return values. Apply it to two different functions and print both results.
Output: complete Python program

Arguments in the Decorated Function

A function that needs arguments can be decorated too, as long as the wrapper function passes those arguments along:

Example

Decorating a function that takes an argument:

Prompt
Create a changecase decorator that works with a function taking one argument. The decorated function should return an uppercased greeting.
Output: complete Python program

*args and **kwargs

A decorator can't always know which arguments the decorated function will receive. The solution is to give the wrapper function the parameters (*args, **kwargs). It can then take any number of arguments of any type and forward them to the decorated function.

Example

Making the wrapper safe with *args and **kwargs:

Prompt
Create a changecase decorator using *args and **kwargs for flexibility. Apply it to a function that takes a name parameter.
Output: complete Python program

Decorator With Arguments

To give a decorator arguments of its own, wrap it in one more level of function.

Example

A decorator factory: the argument it receives decides which casing the output gets.

Prompt
Create a decorator factory changecase that takes an argument n. If n==1, lowercase the result; otherwise uppercase it.
Output: complete Python program

Multiple Decorators

One function can have several decorators.

Simply stack the decorator calls one above the other.

They are applied in reverse order, with the decorator nearest the function going first.

Example

One decorator adds a greeting, and the other converts the text to upper case:

Prompt
Create two decorators: changecase (uppercase) and addgreeting (adds greeting text). Stack both on a function and print the result.
Output: complete Python program

Preserving Function Metadata

Every Python function carries metadata, which you can read through its __name__ and __doc__ attributes.

Decorating a function loses that metadata, though, and the original values are no longer available.

The standard library has a fix: the functools.wraps function keeps the original function's name and docstring in place.

Example

An undecorated function reports its own name through __name__:

Prompt
Show how to access a function's name using the __name__ attribute.
Output: complete Python program

Example

Ask a decorated function for its name and the answer is different:

Prompt
Show that a decorated function loses its original __name__. Print the __name__ of a decorated function.
Output: complete Python program

Example

With functools.wraps imported and applied, the original name and docstring survive.

Prompt
Use functools.wraps to preserve the original function's name when decorating. Print the __name__ of the decorated function.
Output: complete Python program