Вложенные предложения if / else в синтаксической ошибке понимания списка

Начиная со следующего понимания списка:

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]

Теперь я хотел бы добавить условие 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]

Пытался выяснить, как правильно сделать это с помощью списка, но безуспешно.

2 ответа

Решение

Это будет намного проще читать как обычный цикл 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

Ваша проблема в том, что условное выражение всегда должно принимать 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]

хотя условное выражение действительно не предназначено для такого вложения. Это визуально отделяет выражения, которые могут быть добавлены в новый список, от условий, используемых для принятия решения, но я не большой поклонник. Существуют и другие способы форматирования, которые делают различные компромиссы, но 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())

что бы иметь свои плюсы и минусы. (Я думаю, что перечисление их, вероятно, выходит за рамки этого ответа, но оно находится где-то между двумя крайностями понимания единого списка и явным for петля. Это также ближе всего к конструкции, которую я скучаю по моим Perl-дням, do утверждение, которое является чем-то вроде lambda это не принимает никаких аргументов, но может содержать произвольные утверждения.)

Вам необходимо указать else условие, когда ни одно из условий не выполнено. Например:

import re

old_list = ['a', 'b', 'c']

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]

# ['a', 'b', 'c']

Однако это нечитабельно. Я предлагаю, если производительность не является проблемой, вы создаете функцию для обеспечения этой манипуляции со стандартным if / elif / else строит.

Другие вопросы по тегам