Python now has a new statement called
with. Many languages have a
with statement, but they are usually different from the
with statement in Python. In Python, the purpose of
with is to let you set up a block of code that runs under a certain context. When that context finishes after your code runs, it runs some cleanup code.
What is a context? A common example is that of database transactions. With database transactions, you start a transaction, and then make all your changes to the database. Then you can decide whether to undo (or "roll back") all the changes or to commit them (that is, make them permanent), thus finishing the transaction.
While you're making the changes to the database, you're operating under the context of the particular database transaction. The context performs some code when the transaction starts (by creating the transaction and allocating the necessary resources) and then some code at the end (either by committing the changes, or by rolling back the changes). The context is the transaction itself, not the rolling back or committing. Contexts don't necessarily involve rolling back and committing changes.
Another example is that of a file being open. You can open a file, write to the file, and close the file. While writing to the file, you can think of your code as operating under the context of the file. The context, then, would open the file and, when you finish working with it, can handle the task of closing the file for you.
To create a context, create a class that includes the
__exit__() member functions. In the
__enter__() function, write the code that initializes the context (such as opening a file, or starting a database transaction), and in the
__exit__() function either handle any exceptions or just perform the cleanup code. In the case of an exception, the
__exit__() function receives three parameters describing the exception. (Note: For further details on creating your own contexts, see Writing Context Managers in PEP 843.
At first, it could seem like contexts are a bad idea. It seems like they hide away certain vital code (such as closing a file), leaving you unsure of whether the file actually closes. However, that's the case with any library that you use; abstraction hides away certain behavior, but you know that the library is doing the necessary work. The library lightens your work. Think of a context as simplifying your code, taking care of extra details that you otherwise would have to do yourself, as well as ensuring such behavior, much like garbage collection.
Several built-in Python modules and classes now have context management built in. To use them, use the new
with keyword. Before you can use with, however, enable the
from __future__ import with_statement
(You won't have to do this starting with version 2.6.)
These built-in Python objects supporting contexts now have the necessary
__exit__() functions to provide the context management. This will make life much easier in terms of cleanup. Look at the code:
with open('/test.txt', 'r') as f: for line in f: process(line)
By using the
with statement, I don't need to worry about closing the file myself. The code does it for me. Indeed, if after this code runs I try to write the value of
f, I'll see that the file is closed:
>>> print f <closed file '/test.txt', mode 'r' at 0x009E6890>
For me personally, using a context such as this will require a slight shift in my thinking as I write such code, but in the end, it will help us all write code that has fewer bugs, because we won't have to worry about forgetting to close the files or performing other required cleanup code.
A Few Minor Language Changes
Here are a few more changes to the language.
- Dictionaries and missing keys. If you derive a new dictionary class from
dict, you can define a
__missing__(self, key)function to handle retrievals when the key doesn't exist in the dictionary.
rpartitionmethods of the string class. These functions let you split a string on a particular substring, retrieving a tuple containing the substring to the left of the separator, the separator itself, and the substring to the right of the separator.
- Tuples in
endswith. The string methods
endswithmethods already exist for testing whether a string starts or ends with a given substring. Previously, you could only test for the existence of a single substring. Now, with version 2.5, you can pass a tuple to test for the existence of any of a given set of substrings.
Key functions with
max. You can now pass the name of a function to the
maxfunction to evaluate the ordinality of each function. For example, you might determine a string's ordinality with:
def myord(astr): try: num = int(astr) return num except: return len(astr)
Then, given a list of strings, you can evaluate the maximum with the function:
print max(['abc','100','a','xyz','1'], key=myord)
More binary expression functions. Python 2.5 now includes two built-in functions that are useful for binary expressions. The function
any()returns true if any of its items are true. The function
all()returns true only if all items are true. Here's some sample code that shows
>>> a = 10 >>> b = 20 >>> any([a>5, b>5]) True >>> any([a>50, b>50]) False >>> any([a>50, b>5]) True
Python 2.5 includes a few more minor changes that have short descriptions. Rather than reiterate them here, Other Language Changes discusses:
- Support for an
- Support for importing through relative versus absolute paths
- A new
quit()function in the interpreter