I encountered a problem with two pieces of code: one successfully executed, while the other did not, resulting in a ValueError related to an I/O operation on a closed file. Can you explain why one code snippet failed and the other succeeded, highlighting the differences between them?
Invalid
def get_file_rows(path: str):
with open(path, "r") as file:
lines = (line.strip() for line in file)
return lines
lines = get_file_rows("test.txt")
for line in lines:
print(line)
ValueError: I/O operation on closed file.
Valid
def get_file_rows(path: str):
with open(path, "r") as file:
for line in file:
yield line.strip()
lines = get_file_rows("test.txt")
for line in lines:
print(line)
>Solution :
That is because your first sample is equivalent to
def _generator(file):
for line in file:
yield line.strip()
def get_file_rows(path: str):
with open(path, "r") as file:
return _generator(file)
And generator functions like _generator, when called, do not start their execution yet, they only return a generator iterator. That code only gets executed when it is iterated over, by which time control flow has left the with-statement and the file has been closed.
By contrast, in your second example, the with statement is only entered at the start of iteration over lines and only exits after the iterator is exhausted.