# Briefly explaining Python3 Decorators

Decorators are a way to modify behavior of functions using other functions.

Take a look at the following routine:

```
1def sum(x, y):
2 return x + y
```

Say we wanted to alter this function so that it would always return a result by 1 larger than the sum. We can write a decorator for that:

```
1def increment(func):
2 def add_one(x, y):
3 return func(x, y) + 1
4
5 return add_one
6
7@increment
8def sum(x, y):
9 return x + y
```

```
1> sum(5, 4)
210
```

Under the hood, `sum`

becomes `increment(sum)`

, i.e. ** sum = increment(sum)**. The function is modified, i.e.

*by a new function returned by the decorator applied to it, which is why return values of decorators always have to be*

**decorated***(i.e. - functions - though any object that implements the*

**callable****method is considered callabe).**

`__call__`

That’s pretty much all there is to decorators.

This can be a little confusing, so to recap what is happening here:

- The reference to our original
function is passed into its decorator,`sum`

, and it is called`increment`

- From within it we construct a new inner function (
), which is returned, and our original function is overwritten by it`add_one`

- from within this function we call our original
function - passing in any arguments (we have a reference to it!), adding one to its return value and returning it`sum`

- this function has to take in the same number of arguments as the original function, because we intend to call our original function from within this new one

- from within this function we call our original

## Another example

Knowing all this, we can, as an example, create a decorator that simply completely overwrites the result of any function it decorates.

```
1def overwrite(f):
2 return lambda: "OVERWRITTEN"
3
4@overwrite
5def some_complex_routine(*args):
6 # lots of complex logic here...
7 return "some complex result"
```

```
1> some_complex_routine()
2"OVERWRITTEN"
```

Here I use the lambda notation to create and return a simple function using a one-liner.

It is the equivalent of writing this:

```
1def overwrite(f):
2 def inner():
3 return "OVERWRITTEN"
4 return inner
```

## Chaining multiple decorators

Decorating a single function using multiple decorators is possible, and the decorators are applied “from the bottom up” - i.e. the decorator “closest to” the function declaration is the one that gets applied first:

```
1def plusone(func):
2 def addone(x, y):
3 return func(x, y) + 1
4
5 return addone
6
7def divtwo(func):
8 return lambda a, b: func(a, b) / 2
9
10@plusone
11@divtwo
12def sum(x, y):
13 return (x + y)
```

```
1> sum(5, 4)
25.5
```

By observing the result we can see that first ** 5 + 4** was divided by two, and then one was added to result.

## Decorators with parameters

Unfortunately it isn’t as simple as making the decorator function accept additional arguments, and I was quite bummed to find that out.

Instead, a decorator with a parameter should actually be a function that takes an argument and returns a function which in turn returns another function. In other words, we have to call a function with a parameter that will then return a decorator function (built upon that paramater). **You can think of it just like the decorators we’ve written above, but now they are returned from yet another function**. Confusing (and I still don’t understand why, however there is probably a good exaplanation for it), so let’s rewrite the ** divtwo** decorator so that it accepts the number to divide by as an argument:

```
1def divby(n):
2 def decorator(func):
3 def inner(a, b):
4 return func(a, b) / n
5 return inner
6 return decorator
7
8@divby(3)
9def sum(x, y):
10 return (x + y)
```

```
1> sum(5, 4)
23.0
```

Now the decorator has an argument which we can control on a per-function basis.

Since our decorator routine consists of simple one-liner statements we can rewrite it entirely using lambdas, however I personally think that, while more concise, it is less readable:

```
1def divby(n):
2 return lambda func: lambda a, b: func(a, b) / n
```

## Decorating functions regardless of their arguments

The decorators I’ve written so far all assume that the decorated function accepts 2 arguments, and as such only works on those. We can fix this by using the familiar ** *args, **kwargs** notation:

```
1def divby(n):
2 def decorator(func):
3 def inner(*args, **kwargs):
4 return func(*args, **kwargs) / n
5 return inner
6 return decorator
```

Now this decorator can be applied to any function, regardless of the arguments it takes (or does not take!).