Стилизировать многострочные условия в операторах if? - PullRequest
569 голосов
/ 08 октября 2008

Иногда я разбиваю длинные условия в if с на несколько строк. Наиболее очевидный способ сделать это:

  if (cond1 == 'val1' and cond2 == 'val2' and
      cond3 == 'val3' and cond4 == 'val4'):
      do_something

Не очень привлекательно визуально, потому что действие сочетается с условиями. Тем не менее, это естественный способ с использованием правильного отступа Python из 4 пробелов.

На данный момент я использую:

  if (    cond1 == 'val1' and cond2 == 'val2' and
          cond3 == 'val3' and cond4 == 'val4'):
      do_something

Но это не очень красиво. : -)

Можете ли вы порекомендовать альтернативный способ?

Ответы [ 29 ]

615 голосов
/ 08 октября 2008

Вам не нужно использовать 4 пробела во второй условной строке. Может быть, использовать:

if (cond1 == 'val1' and cond2 == 'val2' and 
       cond3 == 'val3' and cond4 == 'val4'):
    do_something

Кроме того, не забывайте, что пробелы более гибкие, чем вы думаете:

if (   
       cond1 == 'val1' and cond2 == 'val2' and 
       cond3 == 'val3' and cond4 == 'val4'
   ):
    do_something
if    (cond1 == 'val1' and cond2 == 'val2' and 
       cond3 == 'val3' and cond4 == 'val4'):
    do_something

Оба они довольно уродливы.

Может быть, потерять скобки ( Руководство по стилю не одобряет это)?

if cond1 == 'val1' and cond2 == 'val2' and \
   cond3 == 'val3' and cond4 == 'val4':
    do_something

Это по крайней мере дает вам некоторую дифференциацию.

Или даже:

if cond1 == 'val1' and cond2 == 'val2' and \
                       cond3 == 'val3' and \
                       cond4 == 'val4':
    do_something

Я думаю, что предпочитаю:

if cond1 == 'val1' and \
   cond2 == 'val2' and \
   cond3 == 'val3' and \
   cond4 == 'val4':
    do_something

Вот Руководство по стилю , которое (с 2010 года) рекомендует использовать скобки.

111 голосов
/ 08 октября 2008

Я прибег к следующему в вырожденном случае, когда это просто AND или OR.

if all( [cond1 == 'val1', cond2 == 'val2', cond3 == 'val3', cond4 == 'val4'] ):

if any( [cond1 == 'val1', cond2 == 'val2', cond3 == 'val3', cond4 == 'val4'] ):

Он бреет несколько символов и дает понять, что в этом условии нет тонкости.

51 голосов
/ 08 октября 2008

Кто-то должен защищать использование вертикальных пробелов здесь! :)

if (     cond1 == val1
     and cond2 == val2
     and cond3 == val3
   ):
    do_stuff()

Это делает каждое условие ясно видимым. Это также позволяет более четко выражать более сложные условия:

if (    cond1 == val1
     or 
        (     cond2_1 == val2_1
          and cond2_2 >= val2_2
          and cond2_3 != bad2_3
        )
   ):
    do_more_stuff()

Да, для ясности мы отменили немного вертикальной недвижимости. Хорошо стоит ИМО.

24 голосов
/ 14 января 2011

Вот мое очень личное мнение: длинные условия - это (на мой взгляд) запах кода, который предполагает рефакторинг в булево-возвращаемую функцию / метод. Например:

def is_action__required(...):
    return (cond1 == 'val1' and cond2 == 'val2'
            and cond3 == 'val3' and cond4 == 'val4')

Теперь, если бы я нашел способ, чтобы многострочные условия выглядели хорошо, я, вероятно, был бы доволен их наличием и пропустил рефакторинг.

С другой стороны, их нарушение моего эстетического ощущения служит стимулом для рефакторинга.

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

23 голосов
/ 08 октября 2008

Это не так сильно улучшится, но ...

allCondsAreOK = (cond1 == 'val1' and cond2 == 'val2' and
                 cond3 == 'val3' and cond4 == 'val4')

if allCondsAreOK:
   do_something
21 голосов
/ 08 октября 2008

Я предпочитаю этот стиль, когда у меня ужасно большое условие if:

if (
    expr1
    and (expr2 or expr3)
    and hasattr(thingy1, '__eq__')
    or status=="HappyTimes"
):
    do_stuff()
else:
    do_other_stuff()
19 голосов
/ 08 октября 2008

Я предлагаю переместить ключевое слово and во вторую строку и сделать отступ для всех строк, содержащих условия, с двумя пробелами вместо четырех:

if (cond1 == 'val1' and cond2 == 'val2'
  and cond3 == 'val3' and cond4 == 'val4'):
    do_something

Именно так я решаю эту проблему в своем коде. Наличие ключевого слова в качестве первого слова в строке делает условие намного более читабельным, а сокращение количества пробелов еще больше отличает условие от действия.

10 голосов
/ 05 июля 2015

Кажется, стоит цитировать PEP 0008 (официальное руководство по стилю Python), так как он комментирует эту проблему в скромной длине:

Когда условная часть if -отношения достаточно длинна, чтобы требовать ее записи в несколько строк, стоит отметить, что комбинация двухсимвольного ключевого слова (т.е. if) плюс один пробел, плюс открывающая скобка создает естественный отступ в 4 пробела для последующих строк многострочного условия. Это может привести к визуальному конфликту с набором кода с отступом, вложенным в if -статейшн, который также естественно будет иметь отступ в 4 пробела. Этот PEP не занимает явной позиции о том, как (или следует) дополнительно визуально отличать такие условные строки от вложенного набора внутри if -отмечения. Приемлемые варианты в этой ситуации включают, но не ограничиваются:

# No extra indentation.
if (this_is_one_thing and
    that_is_another_thing):
    do_something()

# Add a comment, which will provide some distinction in editors
# supporting syntax highlighting.
if (this_is_one_thing and
    that_is_another_thing):
    # Since both conditions are true, we can frobnicate.
    do_something()

# Add some extra indentation on the conditional continuation line.
if (this_is_one_thing
        and that_is_another_thing):
    do_something()

Обратите внимание на «не ограничено» в приведенной выше цитате; кроме подходов, предложенных в руководстве по стилю, некоторые из предложенных в других ответах на этот вопрос также приемлемы.

6 голосов
/ 19 ноября 2014

Вот что я делаю, помните, что «all» и «any» принимает итерируемое, поэтому я просто помещаю длинное условие в список и позволяю «all» делать работу.

condition = [cond1 == 'val1', cond2 == 'val2', cond3 == 'val3', cond4 == 'val4']

if all(condition):
   do_something
4 голосов
/ 07 марта 2013

Лично мне нравится добавлять смысл в длинные операторы if. Мне пришлось бы искать в коде, чтобы найти подходящий пример, но вот первый пример, который приходит на ум: допустим, я случайно натолкнулся на некоторую причудливую логику, где я хочу отобразить определенную страницу в зависимости от многих переменных.

Английский: «Если вошедший в систему пользователь НЕ является учителем-администратором, а просто обычным учителем и не является самим студентом ...»

if not user.isAdmin() and user.isTeacher() and not user.isStudent():
    doSomething()

Конечно, это может выглядеть хорошо, но читать их, если заявления - много работы. Как насчет того, чтобы мы присвоили логику метке, которая имеет смысл. «Метка» - это имя переменной:

displayTeacherPanel = not user.isAdmin() and user.isTeacher() and not user.isStudent()
if displayTeacherPanel:
    showTeacherPanel()

Это может показаться глупым, но у вас может быть еще одно условие, когда вы ТОЛЬКО хотите отображать другой элемент, если и только если вы отображаете панель учителя ИЛИ, если пользователь имеет доступ к этой другой конкретной панели по умолчанию:

if displayTeacherPanel or user.canSeeSpecialPanel():
    showSpecialPanel()

Попробуйте написать вышеупомянутое условие, не используя переменные для хранения и маркировки вашей логики, и вы не только получите очень грязное, трудно читаемое логическое утверждение, но вы также просто повторили себя. Хотя есть разумные исключения, помните: не повторяйте себя (СУХОЙ).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...