Decorators With Parameters

by: George El., March 2019, Reading time: 2 minutes

In this post we will continue on decorators, and I will show you how we can pass parameters to decorators. Please read the previous post Decorators in Python if you are not familiar with decorators. In the previous post we saw this example.

def outerf(fn):
    from datetime import datetime
    def innerf(*args, **kwargs):
        print (datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S.%f'))
        return fn(*args, **kwargs)
    return innerf

def add(a,b):
    return a+b

add = outerf(add)
add(1,2)

What if I want to execute the function 3 times? then I could do something like this

def outerf(fn):
    from datetime import datetime
    def innerf(*args, **kwargs):
        for i in range(3):
            print (datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S.%f'))
            print (fn(*args, **kwargs))
    return innerf

def add(a,b):
    return a+b

add = outerf(add)
add(1,2)

what if I want to make 3 a variable? I could write

def outerf(fn,n):
    from datetime import datetime
    def innerf(*args, **kwargs):
        for i in range(n):
            print (datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S.%f'))
            print (fn(*args, **kwargs))
    return innerf

def add(a,b):
    return a+b

add = outerf(add,3)
add(1,2)

the output is

2019-03-20 17:25:46.812638
3
2019-03-20 17:25:46.813136
3
2019-03-20 17:25:46.813635
3

so this works fine, but if I try to do this I will get an error.

@outerf(3)
def add(a,b):
    return a+b
TypeError: outerf() missing 1 required positional argument: 'n'

if we want to use a decorator with a parameter we need to create another function that will accept the parameter and return our decorator. So the code will look like that:

def outer_outerf(n):
    def outerf(fn):
        from datetime import datetime
        def innerf(*args, **kwargs):
            for i in range(n):
                print (datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S.%f'))
                print (fn(*args, **kwargs))
        return innerf
    return outerf

@outer_outerf(3)
def add(a,b):
    return a+b

add(1,2)

Let me explain, the outer_outerf is not the decorator, but it returns the outerf which is the decorator. So now we can decorate any function with a parameter. For instance

def outer_outerf(n):
    def outerf(fn):
        from datetime import datetime
        def innerf(*args, **kwargs):
            for i in range(n):
                print (datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S.%f'))
                print (fn(*args, **kwargs))
        return innerf
    return outerf

@outer_outerf(4)
def print_hello():
    return "hello"

print_hello()

the above code will print

2019-03-20 17:39:05.838394
hello
2019-03-20 17:39:05.839398
hello
2019-03-20 17:39:05.839398
hello
2019-03-20 17:39:05.839880
hello
comments powered by Disqus