重新使用样板循环结构而不用调用n次子句的pythonic方法

时间:2019-04-05 10:12:25

标签: python

我继承了一个旧的代码库,其中包含大量嵌套的for循环,类似于:

def func(infile, some_other_data, outfile, status_variable):
    with open(infile, 'r') as f:
        with open(outfile, 'w') as outf:
            for line in f:
                # parse line
                for element in some_other_data:
                    standard_function(line, element)
                    if status_variable == 'status_A':
                        function_A(line, element)
                    elif status_variable == 'status_B':
                        function_B(line, element)
                    # handle other possible status variables
                    outf.write(new_line)

此代码与性能有关。为了加快速度(除了其他更改),我希望摆脱所有被称为n * m次的if子句,并且测试表明,这确实可以提高10%。

为此,我只是为每个可能的状态变量复制并修改了主循环函数,并相应地调用了不同的函数。这有效地将if子句移出了循环。但是,它非常丑陋,并且使库变成了原来的4倍。

是否存在一种(相当)简单的python方式来处理这种情况,即我想重用样板循环并仅更改每次迭代所做的操作而无需每次都处理条件?

我一直在与装饰器一起玩,动态地返回循环函数,该循环函数根据状态变量来调用不同的子函数,但是从可读性的角度来看,最终结果看起来很恐怖。我绝不是Python专家,所以我可能忽略了一些方便的高级功能,在这里可能会有所帮助。

任何建议都将受到高度赞赏。

2 个答案:

答案 0 :(得分:5)

理想情况下,您应该传递函数本身而不是状态变量,但是由于这是遗留代码,因此无需更改接口的一种解决方案是设置函数字典,如下所示:

def func(infile, some_other_data, outfile, status_variable,
         status_functions={
             'status_A': function_A,
             'status_B': function_B,
         }
        ):

    try:
        status_function = status_functions[status_variable]
    except KeyError:
        status_function = lambda line, element: None

    with open(infile, 'r') as f, open(outfile, 'w') as outf:
        for line in f:
            # parse line
            for element in some_other_data:
                standard_function(line, element)

                status_function(line, element)
                # handle other possible status variables
                outf.write(new_line)

答案 1 :(得分:3)

如果status_variable-> function_name之间存在直接对应关系,并且所有调用都是常规调用:function(line, element),则可以传入该函数:

def func(infile, some_other_data, outfile, function_from_status_variable):
    with open(infile, 'r') as f:
        with open(outfile, 'w') as outf:
            for line in f:
                # parse line
                for element in some_other_data:
                    standard_function(line, element)

                    function_from_status_variable(line, element)

                    outf.write(new_line)

一次计算,因此:

def calc_function(status_variable):
    if status_variable == 'status_A':
        return function_A
    elif status_variable == 'status_B':
        return function_B
    # other tests follow, plus handle an unknown value

最后调用如下函数:

function = calc_function(status_variable)
func(infile, some_other_data, outfile, function)