Вложенные предложения 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
строит.