Python:如何在函数中避免编写大量的if/elif语句?

3
我已经写了一个作为计算器的函数。它适用于以下变量。
然而,我想将其扩展到处理15个不同的“级别”值以及15个不同的“销售”和“成本”值。该函数将根据以下每个级别应用不同的销售和成本计算方法。(由于每个计算都适用于特定级别,因此这些计算可能会在函数之外定义。)
我可以为每个15个级别编写多个if/elif语句,但这似乎不是很Pythonic。是否有一种方法可以通过编程方式扩展这样的函数来处理更多的销售、级别和成本?
出于清晰起见,输出结果与下面相同(当然取决于输入的值),但该函数应能够处理更多的值。
levels_list = [4, 5]  # ultimately 15 values in this list

sale4 = 18280  # ultimately 15 of these values
sale5 = 19180
sale6 = 22170

cost1 = 224 # and 15 of these values
cost2 = 335
cost3 = 456

def sales(level, foo, bar):
    for level in levels_list: 
        if level == 4:
            x = cost1 + sale4 * foo
            y = cost2 + sale4 * bar
            z = x + y
        elif level == 5:  
            x = cost2 + sale5 * foo
            y = cost3 + sale5 * bar
            z = x + y
            return pd.DataFrame({'Total Cost':[z], 'x_Cost':[x], 'y_Cost':[y]})

sales(5, 10, 10)

    Total Cost  x_Cost  y_Cost
0   384391      192135  192256

1
为什么不把成本和销售价值放入列表中? - Daniel Roseman
3
你需要在数据中寻找规律,例如是否总是cost1 + sale(1+3) * foo。然后你可以将sale和cost的值放入一个数组中,并按位置读取数据。 - Xiongbing Jin
1
将销售价值放入列表中可以解决这个问题,但是你如何确定要使用哪个成本? - Tadhg McDonald-Jensen
3个回答

3

与其为每个成本和销售使用单独的变量,您应该将它们合并为每个列表或字典,具体取决于级别的可能值。根据成本在何种程度上与级别相关以及哪些级别与哪些成本相关的逻辑工作方式,这可以让您基于级别的值访问相应的成本和销售条目。


1
如果最低级别不为0,则列表的索引将会失效(特别是如果级别可以为负数),即使所有键都是整数,使用字典可能更好。 - Tadhg McDonald-Jensen

2

使用dict将相关值与每个级别关联起来是有意义的:

levels_dict = {4 :(sale4, cost1, cost2),
               5 :(sale5, cost2, cost3)}

这样,levels_dict[level] 将为您提供销售额和两个用于计算的成本:
def sales(level, foo, bar):
    sale, x_cost, y_cost = levels_dict[level]
    x = x_cost + sale * foo
    y = y_cost + sale * bar
    ...

如果level in range(15)始终为真,则使用列表可以省去键的需要,您可以使用列表:
levels_data =  [None, #0
                None, #1
                None, #2
                None, #3
                (18280, 224, 335),
                (19180, 335, 456)]

如果级别从4开始,那么这将需要许多占位符。

使用namedtuple可能更好,以确保您始终按正确顺序放置值:

import collections

level = collections.namedtuple("level",["sale","xcost","ycost"])

levels_dict = {4 :level(sale4, cost1, cost2),
               5 :level(sale5, cost2, cost3)}

这仍然与上面的方式一样工作,但还可以使用名称而不是顺序:
def sales(level, foo, bar):
    data = levels_dict[level]
    x = data.xcost + data.sale * foo
    y = data.ycost + data.sale * bar
    ...

dictnamedtuple两种解决方案都很完美。感谢您提供的全面答案。 - RDJ

1
相比于多次测试,你可以将数据组织在一个DataFrame中,例如:
data=pd.DataFrame(np.array([[cost1,cost2,cost3],[sale4,sale5,sale6],
[cost2,cost3,cost4],[sale4,sale5,sale6]]).T,index=[3,4,5],
columns=   ['costx','salex','costy','saley'])

  costx  salex  costy  saley     
3   224  18280    335  18280
4   335  19180    456  19180
5   456  22170    512  22170

以每一行与一个层级相关联的方式进行编程。这样,您的函数将会非常直接:
def sales(level, foo, bar):
        costx,salex,costy,saley=data.loc[level] 
        x = costx + salex * foo
        y = costy + saley * bar
        z = x + y
        return pd.DataFrame({'Total Cost':[z], 'x_Cost':[x], 'y_Cost':[y]})

array() 是从哪里来的? - Tadhg McDonald-Jensen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接