Printing exceptions isn’t the only way we can handle them in the
__exit__ method. An exception that occurs in a context manager can be handled in two ways:
If we want to throw an error when an error occurs, we can either:
- Do nothing
If we want to suppress the error, we can:
Using a script similar to our earlier example, we can examine how this works:
class OpenFile: def __init__(self, file, mode): self.file = file self.mode = mode def __enter__(self): self.opened_file = open(self.file, self.mode) return self.opened_file def __exit__(self, ex_type, ex_val, traceback): print(ex_type, ex_val, traceback) print("The exception has been handled") self.file.close() return True
Notice above that nothing changed except for the adding of
return True to implement the supression of an error. To see this in action, we’ll call two
with statements using this context manager; One that will throw an exception and another that will not. Let’s observe the behavior:
with OpenFile("file.txt", "r") as file: # .see is not a real method print(file.see()) with OpenFile("file.txt", "r") as file: print(file.read())
When we run this code, our output is as follows:
<class 'AttributeError'> '_io.TextIOWrapper' object has no attribute 'see' <traceback object at 0x7fedf822d180> The exception has been handled None None None
Here we see that:
- The error message we manually coded is printed but there is no automatic error message thrown by the program.
If we did not return
True, the second (and all proceeding)
with statements would not have run since an exception would be hit.
Additionally, we can choose to handle a specific exception, while also suppressing it! This is useful if we want our context manager to not block the execution of other code, but also customize the output if a certain exception occurs. Here is an example of working with a
class OpenFile: def __init__(self, file, mode): self.file = file self.mode = mode def __enter__(self): self.opened_file = open(self.file, self.mode) return self.opened_file def __exit__(self, ex_type, ex_val, traceback): if isinstance(exc_value, IndexError): # Handle TypeError here... print("The exception has been handled") return True self.file.close()
if statement that compares
exc_value to a specific exception we are trying to catch. Anything we want to happen for this specific exception can occur in the conditional code block. Lastly, we return
True to make sure we suppress the exception from arising and stopping the rest of our code from running.
Let’s return to our poem context manager from earlier and implement some exception handling!
We are back with our
PoemFiles context manager!
There are currently two
with calls. Run the code to see what exception occurs. In the next step, we will try to handle it!
Looks like our
AttributeError is back in our first
Inside of the
__exit__ method, write a conditional using the
isinstance() function to check if the exception is an
AttributeError. If it is, close the file and return