Example: Coding Termination Actions with try/finally

We saw some simple try/finally examples in the prior chapter. Here’s a more realistic example that illustrates a typical role for this statement:

class MyError(Exception): pass

def stuff(file):
    raise MyError()

file = open('data', 'w')     # Open an output file
try:
    stuff(file)              # Raises exception
finally:
    file.close()             # Always close file to flush output buffers
print('not reached')         # Continue here only if no exception

广告:个人专属 VPN,独立 IP,无限流量,多机房切换,还可以屏蔽广告和恶意软件,每月最低仅 5 美元

In this code, we’ve wrapped a call to a file-processing function in a try with a finally clause to make sure that the file is always closed, and thus finalized, whether the function triggers an exception or not. This way, later code can be sure that the file’s output buffer’s content has been flushed from memory to disk. A similar code structure can guarantee that server connections are closed, and so on.

As we learned in Chapter 9, file objects are automatically closed on garbage collection; this is especially useful for temporary files that we don’t assign to variables. However, it’s not always easy to predict when garbage collection will occur, especially in larger programs. The try statement makes file closes more explicit and predictable and pertains to a specific block of code. It ensures that the file will be closed on block exit, regardless of whether an exception occurs or not.

This particular example’s function isn’t all that useful (it just raises an exception), but wrapping calls in try/finally statements is a good way to ensure that your closing-time (i.e., termination) activities always run. Again, Python always runs the code in your finally blocks, regardless of whether an exception happens in the try block.[75]

When the function here raises its exception, the control flow jumps back and runs the finally block to close the file. The exception is then propagated on to either another try or the default top-level handler, which prints the standard error message and shuts down the program; the statement after this try is never reached. If the function here did not raise an exception, the program would still execute the finally block to close the file, but it would then continue below the entire try statement.

Notice that the user-defined exception here is again defined with a class—as we’ll see in the next chapter, exceptions today must all be class instances in both 2.6 and 3.0.

 


[75] Unless Python crashes completely, of course. It does a good job of avoiding this, though, by checking all possible errors as a program runs. When a program does crash hard, it is usually due to a bug in linked-in C extension code, outside of Python’s scope.