Best use of "open" context manager

Rob Cliffe rob.cliffe at btinternet.com
Sat Jul 6 09:27:52 EDT 2024



On 06/07/2024 12:57, Oscar Benjamin via Python-list wrote:
> On Sat, 6 Jul 2024 at 11:55, Rob Cliffe via Python-list
> <python-list at python.org> wrote:
>> Consider this scenario (which I ran into in real life):
>>       I want to open a text file and do a lot of processing on the lines
>> of that file.
>>       If the file does not exist I want to take appropriate action, e.g.
>> print an error message and abort the program.
>> I might write it like this:
>>
>> try:
>>       with open(FileName) as f:
>>           for ln in f:
>>               print("I do a lot of processing here")
>>               # Many lines of code here .....
>> except FileNotFoundError:
>>       print(f"File {FileName} not found")
>>       sys.exit()
>>
>> but this violates the principle that a "try" suite should be kept small,
>> so that only targeted exceptions are trapped,
>> not to mention that having "try" and "except" far apart decreases
>> readability.
> This is catching a targeted exception (FileNotFoundError) so I think
> it is fine. If the intention is just to call sys.exit() on error then
> I wouldn't worry too much about having too much code in the try. Just
> make sure that you do this in any other place where you open a file as
> well.
>
> One possible improvement is that you could catch the exception and use
> its filename attribute:
>
> except FileNotFoundError as e
>       print(f"File {e.filename} not found")
>
> That way if you did catch the wrong FileNotFoundError then at least
> you print the correct filename.
Good point, Oscar - thank you.  (Even if you did omit the colon on the 
"except" line🙂.  I've often thought we should have "Python without 
colons" as this is a mistake I frequently make.)
>
> Alternatively:
>
> except FileNotFoundError as e
>       if e.filename != FileName:
>            raise  # re-raise if not the intended exception
>       print(f"File {e.filename} not found")
Indeed, that covers all basis.
> For readability I would just move the many lines of code into a
> separate function.
That may not always be convenient (e.g. if the many-lines-of-code needs 
to access a lot of local variables) but fair enough.
Thanks for your answer.
Rob Cliffe
>
> The reason to avoid having too much code in the try mainly applies to
> situations where you are going to do something other than call
> sys.exit() and the exception is overly generic like ValueError or
> TypeError. If the exception can easily be raised by a bug or something
> other than the intended cause then it is bad to catch exceptions
> around a larger block of code.
>
> If it is expected that the caller of a function might have good reason
> to catch the exception and handle it somehow then it is better to make
> a dedicated exception class and raise that instead. When there is only
> one place in the code that raises a particular exception type and only
> one place that catches it then it is usually going to be clear that
> you are catching the expected exception.
>
> --
> Oscar



More information about the Python-list mailing list