как динамически вызывать функцию - PullRequest
0 голосов
/ 21 мая 2019

У меня есть класс, содержащий несколько списков в качестве атрибутов и несколько методов добавления для добавления объекта в определенный список в зависимости от его типа.

Мой код читает CSV-файл, содержащий тип объекта, чтобы создать и добавить его в корзину. Моя проблема в том, что я тестирую тип объекта для вызова правильной функции add с использованием синтаксиса if elif, но это не очень хорошо и сложно поддерживать.

Например

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()

Видите ли вы какие-либо альтернативы блоку if elif?

Спасибо за ваш отзыв.

Ответы [ 2 ]

1 голос
/ 21 мая 2019

Конечно, вам просто нужно динамически создать имя функции и вызвать его.Будьте осторожны, это будет работать, только если my_cart имеет метод add_{{ item name }}.

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)
1 голос
/ 21 мая 2019

Могу ли я предложить более простой дизайн класса.

  • my_item оставлено как есть и другие классы fruit, vegetable etc. удалены

  • shopping_cart изменяется так, что self.items - это словарь, ключом которого является имя элемента, fruit, vegetables, а значениями - список этих элементов

Тогда код может выглядеть следующим образом

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)

Вывод будет выглядеть как

fruit: ['pomme']  vegetable: ['dinde']  meat: ['carotte']  fish: ['saumon']
...