0

I have a class containing several lists as attributes and several add methods to append an object to a specific list based on its type.

My code reads a csv file containing the type of an object in order to create and add it to my cart. My problem is that I'm testing the object type to call the right 'add' function using if elif syntax but this is not very nice and hard to maintain.

For example

import csv


class my_item():
    def __init__(self, name):
        self.name = name


class fruit(my_item):
    pass


class vegetable(my_item):
    pass


class meat(my_item):
    pass


class fish(my_item):
    pass


class shopping_cart():
    def __init__(self):
        self.fruits = []
        self.vegetables = []
        self.meat = []
        self.fish = []

    def add_fruit(self, o):
        self.fruits.append(o)

    def add_vegetable(self, o):
        self.vegetables.append(o)

    def add_meat(self, o):
        self.meat.append(o)

    def add_fish(self, o):
        self.fish.append(o)

    def __str__(self):
        msg = ""
        msg += "{:<25}= {:<5}\n".format('Total', str(len(self.fruits) + len(self.vegetables) + len(self.meat) + len(self.fish)))
        for attrname in vars(self):
            value = getattr(self, attrname)
            if isinstance(value, list):
                msg += "  {:<23}= {:<5}\n".format(attrname, len(value))
        return msg

def main():
    input_f = 'input.csv'
    my_cart = shopping_cart()
    with open(input_f, 'r') as i:
        rows = csv.reader(i, delimiter=';')
        for row in rows:
            item = globals()[row[0]](row[1])
            if item.__class__.__name__ == 'fruit':
                my_cart.add_fruit(item)
            elif item.__class__.__name__ == 'vegetable':
                my_cart.add_vegetable(item)
            elif item.__class__.__name__ == 'meat':
                my_cart.add_meat(item)
            else:
                my_cart.add_fish(item)
    print (my_cart)

if __name__ == '__main__':
    main()

Do you see any alternatives to the if elif block?

Thanks for your feedback.

balkon16
  • 1,338
  • 4
  • 20
  • 40
Simon
  • 323
  • 5
  • 15

2 Answers2

1

May I suggest a simpler class design.

  • my_item is left as it-is and other classes fruit, vegetable etc. are removed

  • shopping_cart is modified such that self.items is a dictionary where the key is the name of item, fruit, vegetables, and the values are the list of those items

Then the code might look like as follows

import csv
from collections import defaultdict


class my_item:
    def __init__(self, name):
        self.name = name


class shopping_cart:

    def __init__(self):
        #Dictionary to hold items
        self.items = defaultdict(list)

    def add_item(self, type, name):

        #Increment the count of the item by 1
        self.items[type].append(name)

    def __str__(self):

        #Iterate through the dictionary and print all key/value pairs
        msg = ""
        for k,v in self.items.items():
            msg += ' {}: {} '.format(k, v)
        return msg.strip()


sc = shopping_cart()
sc.add_item('fruit', 'pomme')
sc.add_item('vegetable', 'dinde')
sc.add_item('meat', 'carotte')
sc.add_item('fish', 'saumon')

print(sc)

The output will look like

fruit: ['pomme']  vegetable: ['dinde']  meat: ['carotte']  fish: ['saumon']
Devesh Kumar Singh
  • 20,259
  • 5
  • 21
  • 40
1

Sure, you just need to create the function name dynamically and call it. Be careful, this will works only if my_cart have add_{{ item name }} method.

def main():
    input_f = 'input.csv'
    my_cart = shopping_cart()
    with open(input_f, 'r') as i:
        rows = csv.reader(i, delimiter=';')
        for row in rows:
            item = globals()[row[0]](row[1])
            item_name = item.__class__.__name__
            item_add_func_name = 'add_{}'.format(item_name)
            item_add_func = getattr(my_cart, item_add_func_name, None)
            if item_add_func and callable(item_add_func):
                item_add_func(item)
            # if item.__class__.__name__ == 'fruit':
            #     my_cart.add_fruit(item)
            # elif item.__class__.__name__ == 'vegetable':
            #     my_cart.add_vegetable(item)
            # elif item.__class__.__name__ == 'meat':
            #     my_cart.add_meat(item)
            # else:
            #     my_cart.add_fish(item)

    print (my_cart)
Fabio Caccamo
  • 1,871
  • 19
  • 21