I have a situation where I have multiple csv files that I want to transform into various objects. So I have something like:
#What works
car = []
with open("car.csv") as csv_file:
data = iter(csv.reader(csv_file))
next(data) # Discard header
for row in data:
car.append(Car(row[0], row[1], row[2])
#What I want to do
car = load("car.csv", Car.__class__)
def load(file, cls):
arr = []
with open(file) as csv_file:
data = iter(csv.reader(csv_file))
next(data) # Discard header
for row in data:
arr.append(cls.__init__(row)) #Should make a new object
return arr
So then I could use load with Car, Boat, Graph, etc. As long as I pass in an orderly list that can satisfy the init function.
The comments gave the answer:
class Car:
def __init__(self, arg1, arg2):
pass # ...
class Boat:
def __init__(self, arg1, arg2, arg3):
pass # ...
def load_csv(filename: str, cls: type) -> list:
arr = []
with open(filename) as csv_file:
data = iter(csv.reader(csv_file))
next(data) # Discard header
for row in data:
arr.append(cls(*row))
return arr
cars = load_csv("car.csv", Car)
Classes are first class objects that can be passed around, so just pass the class in question.
To invoke it, just call the argument that received the class object as if it were the class. In my modification of your code above, I used *row
instead of row
to expand the row into one argument per item in the row (cls(*[arg1, arg2, arg3])
is equivalent to cls(arg1, arg2, arg3)
) -- this way your classes accept arguments as usual, rather than accepting a single argument holding a list of the instantiation arguments.
One other modification would be to use a CSV DictReader and pass the arguments as keyword arguments:
class Car:
def __init__(self, make, model):
pass # ...
def load_csv(filename: str, cls: type):
arr = []
with open(filename) as csv_file:
reader = csv.DictReader(csv_file)
for record in reader:
arr.append(cls(**record))
return arr
cars = load_csv("car.csv", Car)
DictReader
returns each CSV row as a dictionary with keys taken from the header row. This then uses **record
to translate the dictionary into keyword arguments for the invocation.
Given car.csv
as...
"make","model"
"Toyota","Prius"
"Honda","Accord"
"Ford","F150"
This would return the array of 3 cars instantiated as Car(make="Toyota", model="Prius")
, Car(make="Honda", model="Accord")
, and Car(make="Ford", model="F150")
.