1. Computing

Python Decorators, Methods, and Functions

From , former About.com Guide

1. Python's Function Decorators: An Introduction

Decorators were introduced to the Python world as part of the 2.4 release. They have since become increasingly importantin, especially for maintaining and extending Python programs. In order to best grasp the purpose and beneficiality of Python's decorators, it is important to understand what happens when one imports modules.

When a module is imported, the content of that module is inserted into your code at the point it is imported. So, when you import the re module or the sys module, Python stops reading your code when it hits "import <module name>", reads the given module from the code library, and then returns to your code. The module becomes part of the Python bytecode which is then converted to machine readable code for execution.

In this way, the Python library allows the programmer to nuance the pre-written code to a desired specification. Similarly, a decorator allows one to customise the use of a function, adding to it as desired without changing the original function. This discussion will rely on your having a good working knowledge of Python functions and classes. If you need to refresh yourself on functions, see my discussions of the syntax and purpose of Python functions and classes.

2. Python Decorator Precursors: A History of Python's staticmethod()

In Python 2.2, Python's function object model was extended to include a differentiation between methods: static and class. Methods that are static are not referenced outside of the class's methods and attributes. Because they do not interact with the world outside the class, they are consider immutable. To assign this immutability to the method, one used the method staticmethod():

 class Class: 
 Â Â Â Â def method() 
 Â Â Â Â Â Â Â Â ... 
 Â Â Â Â method = staticmethod(method) 
Because static methods never reference and are never referenced outside of the class, they have no need for a self parameter.

[Note: This code is for illustration only. As we are about to see, this syntax has now changed. Of course, Python offers backward compatability for a few versions, but you should use the new syntax, not this.]

3. Python Decorator Precursors: A History of Python's classmethod()

After Python 2.2, methods that received the class itself as an argument were classified as class methods. They were then definable with the classmethod() method.

 class Class: 
 Â Â Â Â def method(cls) 
 Â Â Â Â Â Â Â Â ... 
 Â Â Â Â method = classmethod(method) 
By convention, the argument which holds the class is always the first and is called cls.

Once again, this is for illustration only. After a spirited discussion on the Python language discussion group, a formal syntax has been incorporated for these two methods, and it is called a decorator.

[Note: This code is for illustration only. As we are about to see, this syntax has now changed. Of course, Python offers backward compatability for a few versions, but you should use the new syntax, not this.]

4. Redirecting Python Calls to Functions and Methods

Decorators allow the programmer to redirect a function call in a predictable and manageable fashion. The following is an example of the basic syntax.

 class Class: 
 Â Â Â Â def method(cls) 
 Â Â Â Â Â Â Â Â ... 
 
 Â Â Â Â @method 
 Â Â Â Â def function: 
 Â Â Â Â Â Â Â Â pass 
The goal of this new syntax is to make it easier for programmers to see the interrelationship between methods.

An incidental plus is that one can knit two different pieces of code together very cleanly without editing either the function or the function call. Simply create a function to match the call and have it decorated to the desired function.

This is the basic syntax, but a concrete example is really needed to illustrate this feature. The following pages look at the use of single and multiple decorators for functions and the value they hold for Python programming.

5. Defining the Decoration

In order to use a decorator, one must first have functions to serve that purpose. Let's create two simple functions, each receives a function as its first and only argument and then creates an attribute for that function object.

 >>> def decorate(function): 
 ...    function.attribute = 'I live to decorate ' + function.__name__ + '.' 
 ...    return function 
 ... 
 >>> def ornament(function): 
 ...    function.mantra = 'My existence is as an ornament for ' + function.__name__ + '.' 
 ...    return function 

If you need to refresh yourself on the attributes and methods of function objects, simply type the following at the Python shell prompt (after defining decorate): dir(decorate). One of the attributes is __name__. You will want to pay attention to the value of this attribute in the output of the program.

6. Decorating Functions in Python

Next, we need to decorate some functions. Let's create three functions. The first two will be decorated by decorate and ornament, respectively. The third will be created by both.

 >>> @decorate 
 ... def a(): pass 
 ... 
 >>> @ornament 
 ... def b(): pass 
 ... 
 >>> @decorate 
 ... @ornament 
 ... def c(): pass 

Now simply type the names -- not even the calls of the functions in turn. You will see that they are all residing as objects in memory.

 >>> a 
 <function a at 0xb7de7df4> 
 >>> b 
 <function b at 0xb7de7e2c> 
 >>> c 
 <function c at 0xb7de7e9c> 
But what about the attributes? That is discussed on the next page.

7. Output of the Decorated Functions

When the decorated function is called, the focus of Python is redirected to the decorating function. The decorator becomes a wrapper around the function. So, the name of the function that is called remains as the identity of the function, even when it is referenced by the decorating function.

 >>> a.attribute 
 'I live to decorate a' 
 >>> b.mantra 
 'My existence is as an ornament for b' 
 >>> c.attribute 
 'I live to decorate c' 
 >>> c.mantra 
 'My existence is as an ornament for c' 
Decorators are thus a very elegant way of combining methods and functions without having to re-arrange someone else's code.

In addition to the information presented here, on the Python Software Foundation's website you can find the proposal that lead to decorators, PEP 318, and the introductory discussion about them that accompanied Python 2.4.

©2013 About.com. All rights reserved.