Python Decorators Basics


Introduction to decorators

Decorators introduce a programming paradigm that is not found in statically linked languages, like C++ or Java. Taking advantage of closures and the fact that functions are first class citizens of python, we can easily change the behaviour of them adding a single line of code.

If you have not used dynamic languages before, chances are that you cannot immediately see the value of decorators but as you will learning about them chances are that you are going to change the way you write and think about coding, as you will discover more elegant and efficient ways to implement things that are either very verbose or even impossible to code in traditional statically linked languages. Although there is a small learning curve associated with them, decorators will quickly pay back enough dividend to justify the learning process.

A python decorator is nothing else than a callable object, receiving a callable as a parameter and returning another callable as its return value.

We will start with the simplest possible case of a decorator, which consists of a regular function accepting a function as its parameter, defining a nested function taking the same parameters as the passed one, returning the nested function to the caller.

What I have just described above, can be visualized in the following picture which presents the basic blocks of a python decorator:

decorator-summary

In the following page we will delve in a bit deeper to the concept of decorators, writing a very simplistic program presenting their use.

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.


*