Python 2.5 was released in late September. Gigi Sayfan reviews a handful of the most interesting new language and library features in a DevX article, including changes in exception handling syntax and exception hierarchy, functional programming improvements, new resource management facilities, generator enhancements, and conditional expressions.
When Python 2.5 was released in mid-September, Python developer Andrew Kuchling estimated that the new release contained some 350 patches and over 450 bug fixes since 2.4. In addition to increased stability, Python 2.5 is also faster, due in part to the results of NeedForSpeed, the Python community's one-week coding sprint earlier this year.
However, the most interesting new 2.5 features for developers are several language and library changes. In a recent article, A Parade of New Features Debuts in Python 2.5, Gigi Sayfan provides an overview of some of the most interesting ones.
The first feature Sayfan discusses are changes the exception handling syntax that provide the ability to have an except and a finally block for the same try block:
Prior to 2.5 you couldn't have both an except clause and a finally clause for the same try block. If you wanted to catch exceptions and also to perform some cleanup code afterwards, you had to create a nested try-except block inside a try-finally block. Now, you can have a combined try-except-finally block...
Python 2.5 reorganized the exception classes hierarchy. Exception is not the root exception anymore. Here is the new exception hierarchy:
BaseException is the root of the built-in exception hierarchy and it is a new-style class (subclasses object). The KeyboardInterrupt and SystemExit are now siblings, just as the Exception and not sub-classes were in Python 2.4.
Of new functional programming features in 2.5—contained in the functools module—Sayfan notes that,
Python 2.5 adds partial function application and the built-in functions any() and all().
Partial is a higher-level concept. It allows partial application of functions. This is similar to partial template specialization in C++ except that it's done at runtime and not at compile time. The idea is that if you have a function that accepts some arguments you can feed it only some of these arguments and what you will get is a new function that accepts only the unsupplied arguments. When you invoke it, it uses the original arguments and calls the original function with the union of all the arguments... Partial function application is a generalization of currying, which is the hallmark of languages such as Haskell.
Partial can be used in diverse scenarios such as callback functions, hidden cookies, and API adaption.
Sayfan then turns to the new with operator. with replaces the oft-used try/finally idiom in resource management, possible leading to both cleaner and safer code:
C++ preaches that you should wrap every resource in an object that will take care of the cleanup in its destructor. This idiom is called "Resource Acquisition Is Initialization" (RAII). Is RAII better than an explicit try-finally block?
Usually, it's much better. It allows simpler and more readable code. Rather than write the cleanup code in every place you use the resource, you write it just once—in the resource object destructor. You don't have to introduce a try-finally block with the mandatory nesting and name scoping. It's impossible to forget to call cleanup code...
RAII is exactly the model for the new with statement in Python. It allows you to use a resource (that supports it) in a special with-block and not worry about cleanup...
The with statement supports another idiom, which is similar to the IDisposable interface in C#. If an object has a method named close()... then they can be used as context managers too...
Generators have been a popular feature in previous Python releases, and 2.5 adds a way to pass values into a generator with the send() method:
A generator is an iterator that invents the sequence it iterates as it goes. Generators use a special keyword yield to return values to the outside world whenever their next() method is called (typically in a for loop)... Generators are very versatile[,] they can (and are) used for lazy evaluation, efficient XML parsing, working with infinite sequences and more.
In Python 2.3 and 2.4 generators could just generate values. Starting with Python 2.5 generators can interact with your program for their entire lifetime...
The new interactive send() empowers generators to implement co-routines. Co-routines are resumable functions and can be used to implement cooperative multi-tasking. This is very useful in many domains; simulations, asynchronous network programming and some algorithms are expressed better as co-routines.
The final 2.5 feature Sayfan discusses is a new conditional expression syntax:
Conditional expressions bring the equivalent of C/C++'s ternary operator to Python:
ratio = x/y if x > y else y/x
The condition is in the middle:
result = true_value if condition else false_value
The benefit of this syntax is that you can read it just like English, which is a quality I like in a language. The official excuse/explanation is that in the standard library most conditional expressions evaluate 90 percent of the time to True so the true_value should dominate.
Python 2.5 sports many additional new features. How do you think these features impact productivity with Python?
Especially the new 'try-except' and 'with' statements are very welcome.
Coming from a Java world the old try-catch syntax was a pita, the new one is really Pythonic. Its clean, simple and powerfull.
It's easy to misunderstand the real purpose of the 'with' statement at first (as did I), but once you see its real purpose (as excellently explained by Fredrik Lundh here: http://online.effbot.org/2006_10_01_archive.htm#with) you'll be pleasantly surprised. It'll make your code much more readable.
Python already had some kind of ternary conditional operator for a long time using an and/or hack:
Instead of writing "y if x else z" we can also write
(x and (y,True) or (z,True))
An additional note on the new features discussed in the article. None of these features is really "deep" with regard to Python 2.4 semantics. That means each statement can be defined perfectly in terms of Python 2.4 without adapting any other part of the runtime but the parser / code generator. The with-statement is actually defined in Python 2.4 terms in PEP 243. The try...except...finally unification can be achieved by a "design pattern" using only try and except. The send() functionality can be achieved using objects for passing values into the generator. I guess if there would be less NeedForSpeed Python can be stripped down to a small kernel language and most features could be recreated using a powerfull macro system. Saying this Python starts to remind me to some other well known language ;)
> Python already had some kind of ternary conditional > operator for a long time using an and/or hack: > > Instead of writing "y if x else z" we can also write >
> (x and (y,True) or (z,True)) >
I'll take the ternary operator if I need it, thank you very much.
> An additional note on the new features discussed in the > article. None of these features is really "deep" with > regard to Python 2.4 semantics. That means each statement > can be defined perfectly in terms of Python 2.4 without > adapting any other part of the runtime but the parser / > code generator. The with-statement is actually defined in > Python 2.4 terms in PEP 243. The try...except...finally > unification can be achieved by a "design pattern" using > only try and except. The send() functionality can be > achieved using objects for passing values into the > generator. I guess if there would be less > NeedForSpeed Python can be stripped down to a small > kernel language and most features could be recreated using > a powerfull macro system. Saying this Python starts to > remind me to some other well known language ;)
If you want a small kernel language with a powerful macro system, why not just stick with C? Or use scheme or some other lisp dialect?
While all of the things you say are true, what is wrong with improvements along the more shallow end? To take your argument to its completely illogical conclusion, we should all just be flipping bits in microcode.
Personally I'm all for improvements in syntax and writing more compact and readable code. I've heard people say that python 1.5.2 is the "one true python" based on the same types of arguments you just made. I've been mostly happy with most of the additions to python to date.