Python Decorator Quick-Reference
Tags: python, decorator, quickreference, cheatsheet
Published: 2022-01-10 11:19:40

---
title: Python Decorator Quick-Reference
published: true
description: A simple quick-reference on how to write a decorator
tags: python, decorator, quickreference, cheatsheet
cover_image: https://live.staticflickr.com/8022/7154613457_6b5af29b46_b.jpg
---

<small>([Image (C) Tai Kedzierski](https://www.flickr.com/photos/ducakedhare/7154613457/))</small>

There are plenty of lenghty tutorial posts out there about what Python decorators are, and the step by step incremental construction of one.

But sometimes all we need is a simple quick refresher. Here's mine (also [on Gist](https://gist.github.com/taikedz/47603180e2384a195e8740143a121eb3)).

* [Basic Concepts](#basic-concepts)
* [A simple decorator](#a-simple-decorator)
* [A decorator with parameters](#a-decorator-with-parameters)
* [Example usage](#example-usage)

## Basic concepts

A Python decorator is a special function that can be added above a callable definition (function, class, anything that implements the `__call__()` method)

When a decorated function is called, it is in fact the decorator itself that is called, and the wrapped callable is then normally called by the implementing handler of the decorator.

A Python decorator is comprised of 3 parts:

* name
* wrapped function receiver
* decorator implementation handler

## A simple decorator

In a simple decorator, the name and the function receiver are one. It supplies a handling function, which should call the wrapped function, then return its result. The naming function must return the handler function.

```python
def printres(func): # decorator name, wrapped function receiver

    def handler(*args, **kwargs): # decorator handling function
        res = func(*args, **kwargs)
        print("{}: {}".format("Result", res))
        return res
    return handler

```

## A decorator with parameters

In a parameterised decorator, the name and receiver are separated into two functions. The outermost function names the decorator and takes its parameters. The first inner function is a wrapper to receive the target function.

We need to import functools and use its 'wraps' decorator to munge the handler, since it is displaced by 1 level, and can cause oddities when stack traces are raised, making debugging difficult. The inner function returns the handler, and the outer function returns the inner function receiver.

```python
import functools

def printmsg(message): # decorator name, decorator parameters

    def function_receiver(func): # wrapped function receiver
        @functools.wraps(func) # munge func so that stack traces and call sequences are retained

        def handler(*args, **kwargs): # decorator handling function
            res = func(*args, **kwargs)
            print("{}: {}".format(message, res))
            return res
        return handler
    return function_receiver
```

## Example usage

```python
@printres
def plus(x, y):
    return x+y


@printmsg("minus")
def minus(x, y):
    return x-y


z1 = plus(2,3)
z2 = minus(3,6)

print("Final print: {} // {} ".format(z1,z2))
```

There you go. Quick, visual, easy. Hope this helps someone ...!