How Python decorators are better than Java annotations

This post is not about how to use Python decorators - there are many posts on the internet about this and this one in particular is one of my favorites which faithfully shows up in page one of my Google search on this topic -

http://www.thumbtack.com/engineering/a-primer-on-python-decorators/

Instead this post is about how much I , a primarily Java guy, enjoy the decorators in Python.

Java does have decorators, they are called annotations

Java has annotations, but the problem is that they don’t do much. You annotate your methods or classes with a annotation that you defined, and pass it a few parameters if you want to. But that’s about it - that by itself cannot do anything. You need to define the retention type of the annotation - whether it makes to the compiled byte code or not - and then you need to write some code that can inspect your objects, check if there was an annotation and then do something with the annotated class or method.

Is it good? Is it functional enough? I would say it is a so so solution. For example if I am writing a JUnit test, then putting @Before on any method would make the test runner run that method before every test. This is better than always writing a setup method because in some cases you might want to quickly change the setup method - and this allows for you to do that without commenting some code.

Similarly, the @Test annotation easily lets you specify the timeout for the test or if you are expecting an exception.

But doing anything complex is tough

Lets say that in Java,  I want to measure the time taken by a method to complete. I can,

  • Call that method in a wrapper method and time it there
  • Write an annotation and have an processor that checks for the annotation and times the method
  • Use AspectJ or something like that which can intercept the code execution based on annotations - but this requires additional compile time or runtime weaving to instrument the code.

If for example, I wanted to annotate all methods that I want to be wrapped in a timing method, I cannot do that without an external processor - and this sucks.

It is much easier in Python

See for yourself, the following code is all that I need

from datetime import datetime
def time_this(f):
 print datetime.now()
 def call():
     f()
     print datetime.now()
 return call
@time_this
def add():
 print 1+1
add()

Just by defining a method, I was able to set that as a decorator on another method! No external processor required! This is the flexibility that I would love to have in Java.

Flexibility makes abstraction easier

I took a very trivial case here, but you can do interesting things if it were this easy to decorate and do additional processing. You could execute the decorated method, and put the results in a DB before returning it, send it to a different application on a messaging platform and what not.

The application that will use this decorator does not need to know anything except the decorator syntax.

Written on May 17, 2012