Best use of "open" context manager
Thomas Passin
list1 at tompassin.net
Sat Jul 6 09:40:49 EDT 2024
On 7/6/2024 6:49 AM, Rob Cliffe via Python-list 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.
>
> Or I might write it like this:
>
> try:
> f = open(FileName) as f:
> FileLines = f.readlines()
> except FileNotFoundError:
> print(f"File {FileName} not found")
> sys.exit()
> # I forgot to put "f.close()" here -:)
> for ln in File Lines:
> print("I do a lot of processing here")
> # Many lines of code here .....
>
> but this loses the benefits of using "open" as a context manager,
> and would also be unacceptable if the file was too large to read into
> memory.
>
> Really I would like to write something like
>
> try:
> with open(FileName) as f:
> except FileNotFoundError:
> print(f"File {FileName} not found")
> sys.exit()
> else: # or "finally:"
> for ln in f:
> print("I do a lot of processing here")
> # Many lines of code here .....
>
> but this of course does not work because by the time we get to "for ln
> in f:" the file has been closed so we get
> ValueError: I/O operation on closed file
>
> I could modify the last attempt to open the file twice, which would
> work, but seems like a kludge (subject to race condition, inefficient).
>
> Is there a better / more Pythonic solution?
I usually read the file into a sequence of lines and then leave the
open() as soon as possible. Something like this:
FILENAME = 'this_is_an_example.txt'
lines = None
if os.path.exists(FILENAME):
with open(FILENAME) as f:
lines = f.readlines()
# do something with lines
Of course, if you want to read a huge number of lines you will need to
be more thoughtful about it. Or make all the processing within the
open() block be a function. Then you just have one more line in the block.
More information about the Python-list
mailing list