【问题标题】:how to call function dynamically如何动态调用函数
【发布时间】:2019-10-07 14:35:40
【问题描述】:

我有一个类,其中包含几个列表作为属性和几个添加方法,用于根据对象的类型将对象附加到特定列表。

我的代码读取了一个包含对象类型的 csv 文件,以便创建它并将其添加到我的购物车中。 我的问题是我正在测试对象类型以使用 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 块的替代方案?

感谢您的反馈。

【问题讨论】:

  • 您能补充一下您的input.csv 的样子吗?
  • 你可以做一个访问者样式:item.addTo(my_cart),其中项目知道要调用add_fruit(), add_meat()等中的哪个。
  • 您的代码可能与更简单的类设计有关,请在@Simon 下方查看我的答案
  • 输入的 .csv 看起来像这个水果;pomme 肉;dinde 蔬菜;carotte fish;saumon

标签: python methods dynamic call


【解决方案1】:

当然,您只需要动态创建函数名并调用它。 请注意,这仅在 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)

【讨论】:

    【解决方案2】:

    我可以建议一个更简单的类设计。

    • 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']
    

    【讨论】:

    • 感谢 Devesh,确实重新设计我的课程会简化代码。
    • 不用担心,如果是这样的话,我建议像我一样重新设计这个类,然后相应地重新设计你的main逻辑@Simon :)
    猜你喜欢
    • 2011-05-13
    • 2018-07-07
    • 1970-01-01
    • 1970-01-01
    • 2023-04-06
    • 2012-02-13
    • 2010-11-21
    • 1970-01-01
    相关资源
    最近更新 更多