Home > Back-end >  After you create a class, how do you add information from a csv to a python object, without using a
After you create a class, how do you add information from a csv to a python object, without using a

Time:10-23

I am struggling to understand classes/objects and using a csv with them.

I have a CSV with 26 rows, 1 being the header, the other containing rows of info. Small example below

id,food,food_print,cal1,cal2,expi1999,expi2000,expi2001
1,bun,bun_bun,45.3434,199.32323,23.3333,45.4444,33.33333
2,burger,burger_bun,45.342343,200.34243,34.3333,0,9
3,pickle,pickle_seed,67.345454,34.3434,34,56,33
4,chicken,chicken_egg,44.34343,43.343343,43,434,34343

I have my class as follows:

class City(object):
    def __init__(self, food = 'n/a', foodprint = 'n/a', cal1 = -999, cal2 = -999, 
    expi1999 = -999, expi2000 = -999, expi2001 = -999) 
        self.food = food
        self.foodprint = foodprint
        self.cal1 = cal1
        self.cal2 = cal2
        self.expi1999 = expi1999
        self.expi2000 = expi2000
        self.expi2001 = expi2001

meals = []

foodfile = open('Food.csv', 'rt')
headers = foodfile.readline().strip().split(',')
headers = headers.split(',')

for line in foodfile:
    foodfields = foodfile.readline().strip().split(',')

How do I write in the rows from my food csv into an object to be referenced in the class?

CodePudding user response:

Assuming all colums are filled in every row: try:

for line in foodfile:
    foodfields = foodfile.readline().strip().split(',')
    meals.append(City(foodfields[1],foodfields[2],foodfields[3],foodfields[4],foodfields[5],foodfields[6],foodfields[7]))

CodePudding user response:

true tone to avoid dynamic classes.
Because your code become unpredictable in future changes. Use dataclass instead.
Also this behaviour let you refer to this "data model" as annotation during data exchange with any callable.

from dataclasses import dataclass
@dataclass
class City:
    food: str = 'n/a'
    foodprint: str = 'n/a'
    cal1: int = -999
    cal2: int = -999
    expi1999: int = -999 
    expi2000: int = -999
    expi2001: int = -999

But if you want to now how to do it - setattr function exists in global namespace.

class DynamicContainer:
    @classmethod
    def create(cls, headers: list[str], data: list[str]):
        obj = cls()
        for header, value in zip(headers, data):
            setattr(obj, header, value)
        return obj
        
headers = 'id,food,food_print,cal1,cal2,expi1999,expi2000,expi2001'.split(',')
data = '1,bun,bun_bun,45.3434,199.32323,23.3333,45.4444,33.33333'.split(',')
cont = DynamicContainer.create(headers, data)

print(cont.id, cont.cal1, cont.expi2000)

CodePudding user response:

Here is how I would do it:

import csv

class City(object):
    def __init__(self, food=None, foodprint=None, cal1=None, cal2=None,  expi1999=None, expi2000=None, expi2001=None):
        self.food = food
        self.foodprint = foodprint
        self.cal1 = float(cal1)
        self.cal2 = float(cal2)
        self.expi1999 = float(expi1999)
        self.expi2000 = float(expi2000)
        self.expi2001 = float(expi2001)
        
    def __repr__(self):
        return (
            f"{self.__class__.__name__}("
            f"food={self.food!r}"
            f", "
            f"food_print={self.foodprint!r}"
            f", "
            f"cal1={self.cal1!r}"
            f", "
            f"cal2={self.cal2!r}"
            f", "
            f"expi1999={self.expi1999!r}"
            f", "
            f"expi2000={self.expi2000!r}"
            f", "
            f"expi2001={self.expi2001!r}"
            f")"
        )

with open("Food.csv") as stream:
    next(stream)  # Skip the header row
    reader = csv.reader(stream)
    meals = [City(*row[1:]) for row in reader]

Here is what rows looks like:

[City(food='bun', food_print='bun_bun', cal1=45.3434, cal2=199.32323, expi1999=23.3333, expi2000=45.4444, expi2001=33.33333),
 City(food='burger', food_print='burger_bun', cal1=45.342343, cal2=200.34243, expi1999=34.3333, expi2000=0.0, expi2001=9.0),
 City(food='pickle', food_print='pickle_seed', cal1=67.345454, cal2=34.3434, expi1999=34.0, expi2000=56.0, expi2001=33.0),
 City(food='chicken', food_print='chicken_egg', cal1=44.34343, cal2=43.343343, expi1999=43.0, expi2000=434.0, expi2001=34343.0)]

Notes

  • The repr function is to show the contents of the class object, you can ignore it
  • I use the csv module to ease parsing the CSV data
  • I also converted the values into floating point numbers.
  • Related