Keller Scholl
Keller Scholl

Reputation: 301

New Class doesn't have a setItem Method

So, this is my code.

def classMaker(csv):
    csv = csv.split("/n")
    firstLine = csv[0]
    csv = csv[1:]
    class newClass():
        def __init__(self, line):
            self.vars = firstLine
            for i in range(len(line)):
                self[firstLine[i]] = line[i]
    return [newClass(line) for line in csv]

The problem is an AttributeError in self[firstLine[i]] = line[i]. It says

AttributeError: newClass instance has no attribute '__setitem__'

I don't know why it is causing this error. My goal is to take in a csv file exported from Excel and auto-generate object names from field names.

Thank you in advance.

Upvotes: 1

Views: 2009

Answers (2)

Robᵩ
Robᵩ

Reputation: 168766

If I can infer your intent correctly, you want to replace this line:

self[firstLine[i]] = line[i]

with this:

setattr(self, firstline[i], line[i])

This will create an attribute of your newClass object named after the column in your data.

E.g.:

Name, Date, Weight
Joe, 23-Sep, 99
...

and

data = classMaker('file.csv') 

will produce :

data[0].Name == 'Joe'

P.s. I assume that you will add file I/O, parsing the CSV file, and other missing elements.

P.p.s: You can avoid the loop counter i altogether:

for attr, val in zip(firstLine, line):
  setattr(self, attr, val)

P.p.s: Here is a complete working sample:

import csv

def classMaker(filename):
  class newClass(object):
    def __init__(self, line):
      for attr, val in zip(firstLine, line):
        setattr(self, attr, val)
  with open(filename, 'rb') as csvfile:
    spamreader = csv.reader(csvfile)
    firstLine = spamreader.next()
    return [newClass(line) for line in spamreader]

x = classMaker("/tmp/x.csv")
print x[0].Name

Upvotes: 2

Sean Vieira
Sean Vieira

Reputation: 160043

You can avoid the newClass all together if you use collections.namedtuple:

CSVRow = namedtuple("CSVRow", firstLine)
return [CSVRow(*line) for line in csv]

This assumes that the CSV headers will be valid Python identifiers (that is, if you have entires like "Some Value" this won't work if you don't process firstLine.

This will let you do things like this:

# Let's assume your CSV has a Name field
# and that it is the first column
csv_data[3].Name == csv_data[3][0]
# True

Also, you should look into the csv module to simplify CSV processing.

Upvotes: 3

Related Questions