I am reading an xlsx file (using openpyxl) and a csv (using csv.reader). The openpyxl returns a generator properly, I can iterate over the values in the generator after it is returned from a function that differentiates whether the file is an excel file or a csv. The problem arises when I am doing the same thing with a csv file, you see it returns a generator but I can't iterate over it since the csv file appears to be closed after the function return within the with statement. I know it's obvious that file closes after the with statement has fullfilled it's purpose, but why then does the openpyxl work? why can I still can iterate over the generator of an excel file? and, my ultimate question, how can I make the csv.reader behave the way openpyxl behaves here, i.e. me being able to iterate over the generator values.
import csv
from openpyxl import load_workbook
def iter_rows(worksheet):
"""
Iterate over Excel rows and return an iterator of the row value lists
"""
for row in worksheet.iter_rows():
yield [cell.value for cell in row]
def get_rows(filename, file_extension):
"""
Based on file extension, read the appropriate file format
"""
# read csv
if file_extension == 'csv':
with open(filename) as f:
return csv.reader(f, delimiter=",")
# read Excel files with openpyxl
if file_extension in ['xls', 'xlsx']:
wb2 = load_workbook(filename)
worksheet1 = wb2[wb2.get_sheet_names()[0]]
return iter_rows(worksheet1)
# this works properly
rows = get_rows('excels/ar.xlsx', 'xlsx')
print(rows) # I am: <generator object iter_rows at 0x074D7A58>
print([row for row in rows]) # I am printing each row of the excel file from the generator
# Error: ValueError: I/O operation on closed file
rows = get_rows('excels/ar.csv', 'csv')
print(rows) # I am: <generator object iter_rows at 0x074D7A58>
print([row for row in rows]) # ValueError: I/O operation on closed file