Reputation: 33
I have been trying to create a Class that will accept a CSV file, read it and sort it into a dictionary using one of the rows as a key. Everything i can find online in relation to csv files, deals with them outside of classes.
I am trying to Open the csv file (called books.csv
) and read each row into a private attribute of the Shelf class called __books
that is a dictionary. The dictionary should use the ISBN as a key.
I want to get the csv file books.csv
into the dictionary __books{ }
and put the 4th row as a key but every time I run it, it states that the books.csv
file isn't being read into the dictionary.
The first piece of code is:
class Book:
def __init__(self, title, author, price, isbn):
self.title = title
self.author = author
self.price = price
self.isbn=isbn
def getISBN(self):
return self.isbn
class Shelf:
__books={}
def __init__(self,filename):
f=open(filename, encoding="utf8")
csvreader = csv.reader(f)
for row in csvreader:
abook=Book(row[0],row[1],row[2],row[3])
self.__books[row[4]]=abook
This code will be called into another file and the corresponding code is:
aShelf=Shelf("books.csv")
abook=aShelf._Shelf__books["0743482836"]
if abook.author == "A. Goose":
pass
else:
raise Exception
Upvotes: 0
Views: 162
Reputation: 2784
There are a few issues with the code. Firstly, I think the __books
should be defined as an instance variable, not a class variable. The way you have it, if you create multiple instances of Shelf
they will share the dictionary (I don't think that is the intent).
Secondly, when you are reading files, you should use the with
statement so that you don't leak resources. Thirdly, as some of the comments suggest, you should pass the number of the column that you want to use as a key as an argument.
And lastly, you could provide __getitem__
to allow easier syntax when looking up books.
class Shelf:
def __init__(self,filename, key_no=3):
self._books={}
with open(filename, encoding="utf8") as f:
csvreader = csv.reader(f)
for row in csvreader:
abook = Book(*[x.strip() for x in row])
self._books[row[key_no].strip()] = abook
def __getitem__(self, isbn):
return self._books[isbn]
aShelf=Shelf("books.csv")
print(aShelf._books)
abook = aShelf["0743482836"]
if abook.author == "A. Goose":
pass
else:
raise Exception
Upvotes: 1
Reputation: 21619
I believe your error is that the section that inserts into the dictionary is not indented correctly and so doesn't run when your __init__
method is called
Before
def __init__(self,filename):
f=open(filename, encoding="utf8")
csvreader = csv.reader(f)
for row in csvreader:
abook=Book(row[0],row[1],row[2],row[3])
self.__books[row[4]]=abook
After
def __init__(self,filename):
f=open(filename, encoding="utf8")
csvreader = csv.reader(f)
''' indented here '''
for row in csvreader:
abook=Book(row[0],row[1],row[2],row[3])
self.__books[row[4]]=abook
You can also eliminate the ugly index syntax in your loop by unpacking the values as a tuple
.
NOTE: This section is based on the OPs updated information in comments, relating to which indexes in the csv data represent which book parameters. The earlier sections are not updated.
for _, title, author, price, isbn, *_ in csvreader:
self.__books[isbn] = Book(title, author, price, isbn)
That should be much more readable. The only thing that isnt clear is which index is the isbn, but I'll let you figure that one out.
Upvotes: 0