首页 > 解决方案 > 避免循环中的重复检查

问题描述

很抱歉,如果以前有人问过这个问题。它可能有,但我只是没能找到它。关于这个问题:

我经常使用某些条件初始化循环,这些条件会影响或(停用)其中的某些行为,但不会彻底改变一般循环逻辑。这些条件不会通过循环的操作而改变,但无论如何都必须在每次迭代时检查。有没有办法以pythonic方式优化所述循环以避免每次都进行相同的检查?我知道这将是任何编译语言中编译器的工作,但这里没有编译器。

现在,举一个具体的例子,假设我有一个函数可以解析格式有点像这样的 CSV 文件,但您事先并不知道其中将出现的列:

COL_A,COL_B,COL_F,COL_H,COL_M,COL_T,COL_Z
1,2,3,4,5,6,7
8,9,10,11,12,13,14
...

而且你有这个功能来手动处理文件(我知道有更好的方法来处理 CSV,问题是关于优化循环,而不是关于 CSV 处理)。出于某种原因,列、COL_C和(仅举几例)需要特殊处理。这将导致类似:COL_DCOL_MCOL_N

def process_csv(file):
    with open(file, 'r') as f:
        headers = f.readline().split(',')
        has_C = "COL_C" in headers
        has_D = "COL_D" in headers
        has_M = "COL_M" in headers
        has_N = "COL_N" in headers
        
        for line in f:
            elements = line.split(',')
            if has_C:
                ...  # Special processing related to COL_C
            if has_D:
                ...  # Special processing related to COL_D
            if has_M:
                ...  # Special processing related to COL_M
            if has_N:
                ...  # Special processing related to COL_N
            ...  # General processing, common to all iterations

正如我上面所说,有什么方法可以以某种方式排除支票?对于此示例,它可能不会产生明显的影响,但如果循环中有 50 个特殊条件,则最终每次迭代都会进行 50 次“不必要的”检查。

- - - - - - - - 编辑 - - - - - - - - -

作为我要寻找的另一个示例,这是(非常)邪恶的代码,它通过不对循环进行任何检查来优化循环,而是根据起始条件构建循环本身。我想对于具有许多条件的(非常)长循环,此解决方案最终可能会更快。不过,这取决于 exec 的处理方式,我不确定,因为我发现它可以避免......

def new_process_csv(file):
    with open(file, 'r') as f:
        headers = f.readline().split(',')
        code = \
f'''
for line in f:
    elements = line.split(',')
    {... if "COL_C" in headers else ''}
    {... if "COL_D" in headers else ''}
    {... if "COL_M" in headers else ''}
    {... if "COL_N" in headers else ''}
    ...  # General processing   
'''
        exec(code)

标签: pythonpython-3.xperformance

解决方案


如果您special processing可以重构为特定功能,例如f_C()f_D(),那么您可以制作这些功能的集合:

        has_C = "COL_C" in headers
        has_D = "COL_D" in headers
        has_M = "COL_M" in headers
        has_N = "COL_N" in headers

        functions = [(f_C,has_C), (f_D,has_D), (f_M,has_M), (f_N,has_N)]
        functions = [ff[0] for ff in functions if ff[1]]

        for line in f:
            elements = line.split(',')

            for ff in functions:
                ff()    # although I assume that elements will need to be passed in

        ...  # General processing, common to all iterations

这意味着每次调用都会执行一次测试,process_csv()而不是每次for循环执行一次。


推荐阅读