Learning Python - Mark Lutz [461]
return 1 / x # Python checks for zero automatically
Such asserts are generally superfluous—because Python raises exceptions on errors automatically, you might as well let it do the job for you.[76] For another example of common assert usage, see the abstract superclass example in Chapter 28; there, we used assert to make calls to undefined methods fail with a message.
* * *
[76] In most cases, at least. As suggested earlier in the book, if a function has to perform long-running or unrecoverable actions before it reaches the place where an exception will be triggered, you still might want to test for errors. Even in this case, though, be careful not to make your tests overly specific or restrictive, or you will limit your code’s utility.
with/as Context Managers
Python 2.6 and 3.0 introduced a new exception-related statement—the with, and its optional as clause. This statement is designed to work with context manager objects, which support a new method-based protocol. This feature is also available as an option in 2.5, enabled with an import of this form:
from __future__ import with_statement
In short, the with/as statement is designed to be an alternative to a common try/finally usage idiom; like that statement, it is intended for specifying termination-time or “cleanup” activities that must run regardless of whether an exception occurs in a processing step. Unlike try/finally, though, the with statement supports a richer object-based protocol for specifying both entry and exit actions around a block of code.
Python enhances some built-in tools with context managers, such as files that automatically close themselves and thread locks that automatically lock and unlock, but programmers can code context managers of their own with classes, too.
Basic Usage
The basic format of the with statement looks like this:
with expression [as variable]:
with-block
The expression here is assumed to return an object that supports the context management protocol (more on this protocol in a moment). This object may also return a value that will be assigned to the name variable if the optional as clause is present.
Note that the variable is not necessarily assigned the result of the expression; the result of the expression is the object that supports the context protocol, and the variable may be assigned something else intended to be used inside the statement. The object returned by the expression may then run startup code before the with-block is started, as well as termination code after the block is done, regardless of whether the block raised an exception or not.
Some built-in Python objects have been augmented to support the context management protocol, and so can be used with the with statement. For example, file objects (covered in Chapter 9) have a context manager that automatically closes the file after the with block regardless of whether an exception is raised:
with open(r'C:\misc\data') as myfile:
for line in myfile:
print(line)
...more code here...
Here, the call to open returns a simple file object that is assigned to the name myfile. We can use myfile with the usual file tools—in this case, the file iterator reads line by line in the for loop.
However, this object also supports the context management protocol used by the with statement. After this with statement has run, the context management machinery guarantees that the file object referenced by myfile is automatically closed, even if the for loop raised an exception while processing the file.
Although file objects are automatically closed on garbage collection, it’s not always straightforward to know when that will occur. The with statement in this role is an alternative that allows us to be sure that the close will occur after execution of a specific block of code. As we saw earlier, we can achieve a similar effect with the more general and explicit try/finally statement, but it requires four lines of administrative code instead of one in this case:
myfile = open(r'C:\misc\data')
try:
for line in myfile:
print(line)