- Mastering Objectoriented Python
- Steven F. Lott
- 363字
- 2021-11-12 16:25:21
Cleaning up in a context manager
In this section, we'll discuss a more complex context manager that attempts some cleanup when there are problems.
This addresses the common issue where we want to save a backup copy of a file that our application is rewriting. We want to be able to do something like the following:
with Updating( "some_file" ): with open( "some_file", "w" ) as target: process( target )
The intent is to have the original file renamed to some_file copy
. If the context works normally—no exceptions—then the backup copy can be deleted or renamed to some_file old
.
If the context doesn't work normally—there's an exception—we want to rename the new file to some_file error
and rename the old file to some_file
, putting the original file back the way it was before the exception.
We will need a context manager like the following:
import os class Updating: def __init__( self, filename ): self.filename= filename def __enter__( self ): try: self.previous= self.filename+" copy" os.rename( self.filename, self.previous ) except FileNotFoundError: # Never existed, no previous copy self.previous= None def __exit__( self, exc_type, exc_value, traceback ): if exc_type is not None: try: os.rename( self.filename, self.filename+ " error" ) except FileNotFoundError: pass # Never even got created? if self.previous: os.rename( self.previous, self.filename )
This context manager's __enter__()
method will attempt to preserve a previous copy of the named file if it already exists. If it didn't exist, there's nothing to preserve.
The __exit__()
method be given information about any exception that occurred in the context. If there is no exception, it will simply return any previous file that exists was preserved the file created within the context will also exist. If there is an exception, then the __exit__()
method will try to preserve the output (with a suffix of "error") for debugging purposes it will also put any previous version of file back in place.
This is functionally equivalent to a try-except-finally
block. However, it has the advantage that it separates the relevant application processing from the context management. The application processing is written in the with
statement. The context issues are set aside into a separate class.