Python Beauty

I’ve been playing with Python some more in the past few days (more on that in the close future). The more I use it, the more I love it. The syntax is rich but not absurdly rich like Perl or Ruby. It has a couple of concepts wich are applied throughout the language with no (or very few) special cases. I’ll give two examples of the power of Python: adding a new feature to the language (method synchronization) and some examples of functional-like programming.

I’ll start off with the synchronized decorator. If you want to avoid that multiple threads call a particular data-mutating function at the same time (which can cause data corruption) there are synchronisation features in Python, but they’re not very nice to use. Example:

import thread
someMethod_lock = thread.allocate_lock()
def someMethod():
someMethod_lock.acquire(True) # Wait until lock is released
try:
# Do your stuff
finally:
someMethod_lock.release()

In Java this is easier, you can just mark a method as synchronized:

public synchronized void someMethod() {
// Do your stuff
}

It doesn’t do exactly the same thing (as Java has one lock per object, instead one function/method as kind of implied by this example), but it’s close enough.

I wanted to have this Java feature in Python. I figured out a nice way to do this, in particulary in Python 2.4, which has decorators. First I defined a synchronized function:

def synchronized(fun):
def caller(*params, **kparams):
fun.lock.acquire(True) # Wait
try:
return fun(*params, **kparams)
finally:
fun.lock.release()
fun.lock = thread.allocate_lock()
return caller

Eh? If you’re not famiar with Python you may wonder what I meant with the simplicity-of-Python thing I just mentioned, and rightly so. I just used some fairly esoteric features of Python. First of all I used a function object (fun) as the place to store the lock variable (because everything in Python is an object, including functions). Second, what’s up with that * params, **kparams stuff? I’ll not explain it in detail but what it comes down to is that all the parameters passed to that function are caught in params and all named parameters in kparams. So if you would call the function caller like this: caller(‘Zef’, 5, bla=’hello’) then params would contain [‘Zef’,5] and kparams would contain a hashtable: {‘bla’:’hello’}. The only reason to use this is to kind-of forward all parameters given to caller to the actual function-to-be-called fun. And third, this synchronized function returns a function, which is possible in Python because functions are objects in Python. Confused yet? Don’t worry, it took a while before I grokked it as well. Lots of experimenting help.

Anyway, the thing I wanted to show is what you can do with it and how you can use it.
In Python 2.4 using decorators:

@synchronized
def mySyncedMethod():
# manipulate data

That’s it. Quite close to Java’s syntax eh? Because Python 2.3 doesn’t support decorators yet, it looks less elegant:

def mySyncedMethod():
# manipulate data
mySyncedMethod = synchronized(mySyncedMethod)

Note that the @synchronized decorator is just a fancy way of writing the mySencedMethod = synchronized(mySyncedMethod) line in Python 2.3.

And now for something more simple to understand: some simple functional programming. I think people with some functional programming experience will appreciate this the most. One-line functions in Python can be defined on the fly using the lambda construct, like so:

plusTwo = lambda x: x + 2
print plusTwo(8) # 10

You can nicely apply this feature with the map and filter functions. map applies a function to every item of a list and returns the result. filter tests every element in a list using a function (returning a boolean) and returns all elements for which the function returned True.

numbers = range(10) # 0, 1, 2, ..., 9
print map(lambda x: x*x, numbers) # 0, 1, 4, ..., 81
print filter(lambda x: x % 2 == 0, numbers) # 0, 2, 4, 6, 8

There’s a shorter, more convenient language construct that does the same thing as map:

numbers = range(10) # 0, 1, 2, ..., 9
print [x*x for x in numbers] # 0, 1, 4, ..., 81

Why don’t you do like, for example, “Sam Gentile”:http://samgentile.com/blog/archive/2004/12/27/12406.aspx (a C# MVP) and make learning Python a new year’s resolution? You won’t regret it.