Python Decorators Basics

Adding parameters to decorators

In the previous page we simplified our code by using a decorator to handle exceptions keeping clear the implementation of a function. This is a great improvement over repeating the same code over and over for each function we write but someone might make the case that this solution is very generic and we might need more control over the implementation of the decorator to specify its behaviour.

This can be accomplished by a decorator with parameters which is slightly more complicated than a parameter-less one and it can be done by nesting our current decorator within a higher level function which will now become the real decorator.

Continuing our example, let’s assume that we can solve our problem by using a boolean called that will either make our handler to print the message or not. Based on this our decorator should now look like this:

def handle_exceptions(foo):
def inner(*args, **kargs):
try:
foo(*args, **kargs)
except Exception as ex:
if print_message:
print ex
return inner
return handle_exceptions

The question now is, how we can pass the print_message boolean that is used in the exception handler. Very easy! We just wrap our function within a higher level function which takes a single parameter print_message and now this new function becomes our decorator. This can be seen in the following snippet:

def handle_exceptions_ex(print_message):
def handle_exceptions(foo):
def inner(*args, **kargs):
try:
foo(*args, **kargs)
except Exception as ex:
if print_message:
print ex
return inner
return handle_exceptions

Now, the decorator part for our functions should change to the following:

@handle_exceptions_ex(True)
def print_file(filename):

and

@handle_exceptions_ex(True)
def divide(x,y):

the whole program should look like this now:

#!/usr/bin/python

def handle_exceptions_ex(print_message):
def handle_exceptions(foo):
def inner(*args, **kargs):
try:
foo(*args, **kargs)
except Exception as ex:
if print_message:
print ex
return inner
return handle_exceptions

@handle_exceptions_ex(True)
def print_file(filename):
f = open(filename)
print f.read()

@handle_exceptions_ex(True)
def divide(x,y):
a = x/y
return x / y

print_file('nonexistent_file')

In this posting we covered the basics of python decorators. There are more advanced uses of them that we will talk about in the next postings.

6 Comments

  1. Interesting & was well explained, but curiously – I get an Error:

    python -i Testing.py
    Python 2.7.6 (default, Mar 22 2014, 22:59:38)
    [GCC 4.8.2] on linux2 <- Lubuntu 14.04

    Traceback (most recent call last):
    File "Testing.py", line 13, in
    @handle_exceptions_ex(True)
    TypeError: ‘NoneType’ object is not callable

    #!/usr/bin/python
    import sys

    def handle_exceptions_ex(print_message):
    def handle_exceptions(foo):
    def inner(*args, **kargs):
    try: foo(*args, **kargs)
    except Exception as ex:
    if print_message: print ex
    return inner
    return handle_exceptions

    @handle_exceptions_ex(True)
    def print_file(filename):
    f = open(filename)
    print f.read()

    @handle_exceptions_ex(True)
    def divide(x,y):
    a = x/y
    return x / y

    #divid(2, 0)
    print_file(‘nonexistent_file’)

  2. Verify that the “return inner” is aligned with “def inner(*args, **kargs):”
    Although your code is not aligned properly, I think that the “return inner” is aligned one tab to the right, causing your decorated function to return None

    def handle_exceptions_ex(print_message):
        def handle_exceptions(foo):
            def inner(*args, **kargs):
                    try: 
                        foo(*args, **kargs)
                    except Exception as ex:
                        if print_message: print ex
            return inner
        return handle_exceptions
    
    

Leave a Reply

Your email address will not be published.


*