Is there a better / more Pythonic solution?
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
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?
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?
Best wishes
Rob Cliffe
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?
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 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
try:
f = open( FileName )
except FileNotFoundError:
print( f"File {FileName} not found" )
sys.exit()
else:
with f:
# put this into a separate function if it gets too long here.
for ln in f:
print( "I do a lot of processing here" )
# Many lines of code here .....
On 06Jul2024 11:49, Rob Cliffe <[email protected]> wrote:Did you test 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 .....
What about this:
try:
f = open(FileName) as f:
except FileNotFoundError:
print(f"File {FileName} not found")
sys.exit()
with f:
... process the lines here ...
Remember, the `open()` call returns a file object _which can be used
as a context manager_. It is separate from the `with` itself.
Remember, the `open()` call returns a file object _which can be usedDid you test this?
as a context manager_. It is separate from the `with` itself.
f = open(FileName) as f:
is not legal syntax.
it's legal, but doesn't work (trying to access the file after "with f"
raises the same
ValueError: I/O operation on closed file.
it's legal, but doesn't work (trying to access the file after "with f"
raises the same
ValueError: I/O operation on closed file.
On Sat, 6 Jul 2024 at 11:55, Rob Cliffe via Python-list <[email protected]> wrote: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
Consider this scenario (which I ran into in real life):This is catching a targeted exception (FileNotFoundError) so I think
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.
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.
Alternatively:Indeed, that covers all basis.
except FileNotFoundError as e
if e.filename != FileName:
raise # re-raise if not the intended exception
print(f"File {e.filename} not found")
For readability I would just move the many lines of code into aThat may not always be convenient (e.g. if the many-lines-of-code needs
separate function.
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
Or like below, although pylint complains about this: "consider using
with". Less indentation this way.
f = None
try:
f = open(FILENAME)
records = f.readlines()
except Exception:
sys.exit(1)
| Sysop: | Keyop |
|---|---|
| Location: | Huddersfield, West Yorkshire, UK |
| Users: | 715 |
| Nodes: | 16 (3 / 13) |
| Uptime: | 03:40:23 |
| Calls: | 12,099 |
| Calls today: | 7 |
| Files: | 15,003 |
| Messages: | 6,517,881 |