List Comprehension语法错误中嵌套的if/else子句

fab*_*ber 1 python list-comprehension python-3.x

从以下列表理解开始:

new_list = [re.sub(r'replace_a', 'with__b', i)
             if not re.findall(r'find_pattern', i, re.M) else 
            re.sub(r'replace_c', r'with__d', i)
            for i in old_list]
Run Code Online (Sandbox Code Playgroud)

现在我想添加一个if条件,else然后使用替换另一个模式re.sub().我尝试过:

new_list = [re.sub(r'replace_a', 'with_b', i)
             if not re.findall(r'find_pattern', i, re.M) else
           (re.sub(r'replace_c', r'with_d', i)
             if foo == re.match("pattern", foo))
           for i in old_list]
Run Code Online (Sandbox Code Playgroud)

试图通过列表推导找出正确的方法,但没有运气.

che*_*ner 5

这将作为常规for循环更容易阅读:

new_list = []
for i in old_list:
    if not re.findall(r'find_pattern', i, re.M):
        new_list.append(re.sub(r'replace_a', 'with_b', i))
    elif foo == re.match("pattern", foo):
        new_list.append(re.sub(r'replace_c', r'with_d', i))
    # else:
    #    i
Run Code Online (Sandbox Code Playgroud)

你的问题是条件表达式必须总是带一个else子句,因为它必须有一些值,无论条件是否为真.但是,通过if 声明,您可以省略else.例如,上述内容能够new_list缩短old_list,而不是每次都i需要调用new_list.append.将else结果取消注释与jpp的答案相同的结果.

如果您坚持使用列表推导,那么您可以对其进行格式化以使其更具可读性.考虑

new_list = [re.sub(r'replace_pattern_a', 'with_pattern_b', i)
               if not re.findall(r'find_pattern', i, re.M) else 
            re.sub(r'replace_pattern_c', r'with_pattern_d', i) 
               if foo == re.match("pattern", foo) else
            i
            for i in old_list]
Run Code Online (Sandbox Code Playgroud)

虽然条件表达式确实不是为这种嵌套而设计的.这在视觉上将可以添加到新列表中的表达式与用于做出决定的条件分开,但我不是一个大粉丝.还有其他格式可以做出不同的权衡取舍,但IMO的常规for循环是优越的.


正如jpp所提到的,重构的另一种方法是定义生成器函数:

def foo(old_list):
    for i in old_list:
        if not re.findall(r'find_pattern', i, re.M):
            yield re.sub(r'replace_a', 'with_b', i))
        elif foo == re.match("pattern", foo):
            yield re.sub(r'replace_c', r'with_d', i))
        else:
            yield i

new_list = list(foo())
Run Code Online (Sandbox Code Playgroud)

这也有其优点和缺点.(我认为列举这些可能超出了这个答案的范围,但它确实介于单个列表理解和显式for循环的两个极端之间.它也最接近我错过Perl时代的构造,do声明,这类似于lambda不带任何参数的东西,但可以包含任意语句.)