【问题标题】:Sorting CSV into a dictionary in a Class将 CSV 排序到类中的字典中
【发布时间】:2015-05-04 11:31:54
【问题描述】:

我一直在尝试创建一个接受 CSV 文件的类,读取它并使用其中一行作为键将其排序到字典中。我可以在网上找到的与 csv 文件相关的所有内容都在课堂之外处理。

我正在尝试打开 csv 文件(称为 books.csv)并将每一行读入名为 __books 的 Shelf 类的私有属性中,这是一个字典。字典应该使用 ISBN 作为键。

我想将 csv 文件 books.csv 放入字典 __books{ } 并将第 4 行作为键,但每次我运行它时,它都会指出 books.csv 文件没有被读入字典.

第一段代码是:

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

这段代码会被调用到另一个文件中,对应的代码是:

aShelf=Shelf("books.csv")
    abook=aShelf._Shelf__books["0743482836"]
    if abook.author == "A. Goose":
        pass
    else:
        raise Exception

【问题讨论】:

  • 导入字典是什么意思?您现在无法正常工作的原因是什么?
  • 很抱歉,如果不清楚。实际问题是:打开 csv 文件(称为“books.csv”)并将每一行读入名为 __books 的 Shelf 类的私有属性,该属性是一个字典。字典应该使用 ISBN 作为键。我想将 csv 文件“books.csv”放入字典 __books{} 中,并将第 4 个拖曳作为键,但每次我运行它时,它都会指出“books.csv”文件没有被读入字典.
  • 我认为这是由于从for row in csvreader 开始的块的缩进。如果您将其转移到一个级别,那么它将成为您的 __init__ 方法的一部分并且应该可以工作。
  • 另一件不清楚的事情是,您将 isbn 指定为 Book 构造函数的第四个参数,并在创建书籍时将 row[3] 作为该值传递。然后使用 row[4] 作为dict 键。那么isbn是索引3还是4?如果您将它用作dict 的密钥,您可以在适当的情况下从Book 类中省略 if 并避免数据冗余。
  • 对不起,这是我的错,它在我的代码中缩进了,然后它就不起作用了。我还稍微更改了行,因为它与 csv 文件不正确对应,因此现在用于 csvreader 中的行:abook=Book(row[1],row[2],row[4],row[5]) self. __books[row[5]]=abook 这使得 row[1]=title, row[2]=author, row[4]=price 和 row[5]=isbn 与 csv 文件中的一样。

标签: python class csv dictionary


【解决方案1】:

代码存在一些问题。首先,我认为__books 应该定义为实例变量,而不是类变量。按照您的方式,如果您创建多个 Shelf 实例,它们将共享字典(我认为这不是本意)。

其次,在读取文件的时候,应该使用with语句,这样才不会泄露资源。第三,正如一些 cmets 建议的那样,您应该将要用作键的列号作为参数传递。

最后,您可以提供__getitem__ 以便在查找书籍时使用更简单的语法。

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

【讨论】:

  • 我从来不知道这意味着我的类变量 +1。
【解决方案2】:

我认为您的错误是插入字典的部分没有正确缩进,因此在调用 __init__ 方法时不会运行

之前

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

之后

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

您还可以通过将值解包为tuple 来消除循环中丑陋的索引语法。

注意:本节基于 cmets 中的 OPs 更新信息,涉及 csv 数据中的哪些索引代表哪些书籍参数。前面的部分没有更新。

for _, title, author, price, isbn, *_ in csvreader:
    self.__books[isbn] = Book(title, author, price, isbn)

这应该更具可读性。唯一不清楚的是哪个索引是 isbn,但我会让你弄清楚。

【讨论】:

    猜你喜欢
    • 2015-07-06
    • 2018-01-10
    • 1970-01-01
    • 2019-09-04
    • 2021-12-25
    • 2021-12-24
    • 2017-02-11
    • 2015-06-13
    • 2011-05-18
    相关资源
    最近更新 更多