Recently I came across a strange behavior of the with open() statement in Python. The following code returns output just for the first read-statement, having an empty lines-list.
input_csv = []
with open(self.path, 'r') as f: # Opening the CSV
r = csv.DictReader(f)
for row in r:
input_csv.append(row) # Storing its contents in a dictionary for later use
lines = f.readlines() # Reading it in as a list too
f.close()
While splitting it into two open () statements returns the objects as desired.
input_csv = []
with open(self.path, 'r') as f: # Opening the CSV
r = csv.DictReader(f)
for row in r:
input_csv.append(row) # Storing its contents in a dictionary for later use
f.close()
with open(self.path, 'r') as f: # Opening the CSV
lines = f.readlines() # Reading it in as a list too
f.close()
Why is the f variable just used once in the first statement?
Many thanks
If you look into documentation of csv.reader()
which is used for DictReader().reader
:
Return a reader object which will iterate over lines in the given csvfile. csvfile can be any object which supports the iterator protocol and returns a string each time its
__next__()
method is called...
Hence, it uses behavior of file-like object for which each iteration essentially is f.readline()
. An operation which also advances current position in the file... until EOF is reached, which when iteration raises StopIteration
exception. It is the same behavior you would observe trying:
with open(self.path, 'r') as f:
for l in f:
pass # each line was read
print(f.readlines())
You can add print(f.tell())
to see how the position changes as you execute each line.
If you (re)open a new file, you start at position 0
(again). If you've read through once and wanted to use the same handle again, you need to return to the beginning of the file: f.seek(0)
.
Note: you really do not need to perform f.close()
in a managed context using with
. Once you leave it, it'll close the file handle for you.