Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python decorators theory

I have question about clean thory in Python. When:

@decorator_func
def func(bla, alba):
    pass

Is equivalent to:

def func(bla, alba):
    pass
func = decorator_func(func)

So:

@decorator_func(aaa, bar)
def func(bla, alba):
    pass

Is equvalent to...?

like image 999
Radosław Miernik Avatar asked Jan 16 '23 09:01

Radosław Miernik


2 Answers

It's equivalent to:

def func(bla, alba):
    pass
func = decorator_func(aaa, bar)(func)

Or:

def func(bla, alba):
    pass
decorator = decorator_func(aaa, bar)
func = decorator(func)

So in your second example, decorator_func should be a callable that returns a callable.

Here's an example of such a construction:

class prepend_two_arguments:
    def __init__(self, a, b):
        self.a = a
        self.b = b

    def __call__(self, f):
        def wrapped_function(*args, **kwargs):
            return f(self.a, self.b, *args, **kwargs)
        return wrapped_function

@prepend_two_arguments(1,2)
def f(a, b, c):
    return a+b+c
print(f(3)) # 6

And another one, using only functions:

def add_to_result(x):
    def decorator(fn):
        def wrapped_function(*args, **kwargs):
            return fn(*args, **kwargs)+x
        return wrapped_function
    return decorator

@add_to_result(3)
def my_func(a, b):
    return a+b
print(my_func(1,2)) # 6
like image 93
Oleh Prypin Avatar answered Jan 18 '23 22:01

Oleh Prypin


Here's an example of a decorator function that works using closures:

def print_string_before(string):
    def decorator_fn(fn):
        def wrapped_fn(*args, **kwargs):
            print string
            return fn(*args, **kwargs)
        return wrapped_fn
    return decorator_fn

Note that decorators can equally return the decorated function (or class), having modified it in some way (e.g. setting an attribute).

like image 25
ecatmur Avatar answered Jan 18 '23 22:01

ecatmur