Стилизация многострочных условий в операторах 'if'?

StackOverflow https://stackoverflow.com/questions/181530

Вопрос

Иногда я нарушаю длительные условия в 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

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

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

Это было полезно?

Решение

Вам не нужно использовать 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 года) рекомендует использовать скобки.

Другие советы

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

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

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

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

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

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()

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

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

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

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

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

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

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

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

if allCondsAreOK:
   do_something

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

if (
    expr1
    and (expr2 or expr3)
    and hasattr(thingy1, '__eq__')
    or status=="HappyTimes"
):
    do_stuff()
else:
    do_other_stuff()

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

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

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

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

  

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

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

Вот что я делаю, помните, что " все " и "любой" принимает итерируемое, поэтому я просто помещаю длинное условие в список и позволяю " всем " делай работу.

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

if all(condition):
   do_something

Я удивлен, что не вижу своего предпочтительного решения,

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

Поскольку и - это ключевое слово, оно выделяется моим редактором и выглядит достаточно иначе, чем do_something ниже.

Лично мне нравится добавлять смысл в длинные операторы 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()

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

"все" и "любой" хороши для многих условий однотипного случая.НО они всегда оценивают все условия.Как показано в этом примере:

def c1():
    print " Executed c1"
    return False
def c2():
    print " Executed c2"
    return False


print "simple and (aborts early!)"
if c1() and c2():
    pass

print

print "all (executes all :( )"
if all((c1(),c2())):
    pass

print

(Я слегка изменил идентификаторы, так как имена фиксированной ширины не представляют реальный код & # 8211; по крайней мере, не реальный код, с которым я сталкиваюсь & # 8211; и поверим в читаемость примера.)

if (cond1 == "val1" and cond22 == "val2"
and cond333 == "val3" and cond4444 == "val4"):
    do_something

Это хорошо работает для " и " и "или" (важно, чтобы они были первыми на второй строчке), но гораздо меньше для других длительных условий. К счастью, первое, кажется, является более распространенным случаем, в то время как второе часто легко переписывается с помощью временной переменной. (Обычно это не сложно, но может быть сложно или гораздо менее очевидно / читабельно сохранить короткое замыкание «и» или «при переписывании».)

Поскольку я нашел этот вопрос в в вашем блоге о C ++ я добавлю, что мой стиль в C ++ идентичен:

if (cond1 == "val1" and cond22 == "val2"
and cond333 == "val3" and cond4444 == "val4") {
    do_something
}

В дополнение к тому, что сказал @krawyoti ... Длительные условия пахнут, потому что их трудно читать и трудно понять. Использование функции или переменной делает код более понятным. В Python я предпочитаю использовать вертикальное пространство, заключать в скобки и размещать логические операторы в начале каждой строки, чтобы выражения не выглядели как «плавающие».

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

Если условия необходимо оценивать более одного раза, как в цикле while , тогда лучше использовать локальную функцию.

Простой и простой, также проходит проверку pep8:

if (
    cond1 and
    cond2
):
    print("Hello World!")
<Ч>

В последнее время я предпочел функции all и any , так как я редко смешиваю сравнения And и Or, это работает хорошо, и имеет дополнительное преимущество Failing Early с пониманием генераторов:

if all([
    cond1,
    cond2,
]):
    print("Hello World!")

Просто не забудьте передать одну итерацию! Передача N-аргументов неверна.

Примечание: any похож на многие сравнения или , all похож на многие сравнения и .

<Ч>

Это прекрасно сочетается с пониманием генератора, например:

# Check if every string in a list contains a substring:
my_list = [
    'a substring is like a string', 
    'another substring'
]

if all('substring' in item for item in my_list):
   print("Hello World!")

# or

if all(
    'substring' in item
    for item in my_list
):
    print("Hello World!")

Подробнее о: понимании генератора

Что, если мы только вставим дополнительную пустую строку между условием и телом, а все остальное сделаем каноническим способом?

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

    do_something

p.s.Я всегда использую табуляции, а не пробелы;Я не могу точно настроить...

Просто несколько других случайных идей для полноты картины. Если они работают на вас, используйте их. В противном случае вам, вероятно, лучше попробовать что-то другое.

Вы также можете сделать это с помощью словаря:

>>> x = {'cond1' : 'val1', 'cond2' : 'val2'}
>>> y = {'cond1' : 'val1', 'cond2' : 'val2'}
>>> x == y
True

Эта опция более сложная, но вы также можете найти ее полезной:

class Klass(object):
    def __init__(self, some_vars):
        #initialize conditions here
    def __nonzero__(self):
        return (self.cond1 == 'val1' and self.cond2 == 'val2' and
                self.cond3 == 'val3' and self.cond4 == 'val4')

foo = Klass()
if foo:
    print "foo is true!"
else:
    print "foo is false!"

Не знаю, работает ли это для вас, но это еще один вариант для рассмотрения. Вот еще один способ:

class Klass(object):
    def __init__(self):
        #initialize conditions here
    def __eq__(self):
        return (self.cond1 == 'val1' and self.cond2 == 'val2' and
               self.cond3 == 'val3' and self.cond4 == 'val4')

x = Klass(some_values)
y = Klass(some_other_values)
if x == y:
    print 'x == y'
else:
    print 'x!=y'

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

(И для справки: если это всего лишь один раз, вам, вероятно, лучше использовать метод, который вы представили сначала. Если вы проводите сравнение во многих местах, эти методы могут улучшить читаемость достаточно, чтобы вы не чувствовали себя так плохо из-за того, что они вроде хакеры.)

Что я обычно делаю, это:

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

Таким образом, закрывающая скобка и двоеточие визуально обозначают конец нашего условия.

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

if bool(condition1 and
        condition2 and
        ...
        conditionN):
    foo()
    bar()

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

Как ни странно, когда я писал это и думал о "проблеме", мне пришло в голову еще один идея, которая устраняет накладные расходы на вызов функции.Почему бы не указать, что мы собираемся ввести сложное условие, используя дополнительные пары круглых скобок?Скажем, еще 2, чтобы дать хороший отступ в 2 пробела для подусловий относительно тела оператора if.Пример:

if (((foo and
      bar and
      frob and
      ninja_bear))):
    do_stuff()

Мне это вроде как нравится, потому что, когда ты смотришь на это, в твоей голове сразу же звенит колокольчик, говорящий: "эй, здесь происходит какая-то сложная вещь!".Да, я знаю, что круглые скобки не улучшают удобочитаемость, но эти условия должны появляться достаточно редко, и когда они появятся, вам все равно придется остановиться и внимательно прочитать их (потому что они сложный).

Во всяком случае, еще два предложения, которых я здесь не видел.Надеюсь, это кому-то поможет :)

Вы можете разбить его на две строки

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

Или даже добавьте одно условие за раз. Таким образом, по крайней мере, он отделяет беспорядок от if .

Я знаю, что эта ветка старая, но у меня есть некоторый код Python 2.7, и PyCharm (4.5) все еще жалуется на этот случай:

if foo is not None:
    if (cond1 == 'val1' and cond2 == 'val2' and
        cond3 == 'val3' and cond4 == 'val4'):
            # some comment about do_something
            do_something

Даже с предупреждением PEP8 "визуально с отступом строки с тем же отступом, что и у следующей логической строки", фактический код полностью в порядке? Это не "чрезмерный отступ"?

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

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

Даже ответ PEP 0008 отталкивающий.

Вот гораздо более читаемый подход

condition = random.randint(0, 100) # to demonstrate
anti_conditions = [42, 67, 12]
if condition not in anti_conditions:
    pass

Хочешь, чтобы я съел мои слова? Убедите меня, что вам нужны мультиусловия, и я буквально напечатаю это и съест это для вашего развлечения.

Я думаю, что решение @ zkanda было бы хорошо с незначительным поворотом. Если у вас есть ваши условия и значения в их соответствующих списках, вы можете использовать их для сравнения, что сделало бы вещи более общими для добавления пар условие / значение.

conditions = [1, 2, 3, 4]
values = [1, 2, 3, 4]
if all([c==v for c, v in zip(conditions, values)]):
    # do something

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

if (condition1==value1) and (condition2==value2) and \
   (condition3==value3) and (condition4==value4):

И просто предложить другое решение с помощью Оператор iand :

proceed = True
for c, v in zip(conditions, values):
    proceed &= c==v

if proceed:
    # do something

Упакуйте свои условия в список, затем сделайте что-нибудь. как:

if False not in Conditions:
    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

Нет причины, по которой отступ должен быть кратен 4, например, см. "Выровнен с открывающим разделителем":

http: //google-styleguide.googlecode. ком / SVN / багажник / pyguide.html? showone = Отступ # Отступы

Вот еще один подход:

cond_list = ['cond1 == "val1"','cond2=="val2"','cond3=="val3"','cond4=="val4"']
if all([eval(i) for i in cond_list]):
 do something

Это также позволяет легко добавлять другое условие без изменения оператора if, просто добавляя другое условие в список:

cond_list.append('cond5=="val5"')

Я обычно использую:

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

если наш if & amp; условие else должно выполнить несколько операторов внутри него, чем мы можем написать, как показано ниже. Каждый раз, когда у нас есть, если еще пример с одним утверждением внутри него.

Спасибо, это работает для меня.

#!/usr/bin/python
import sys
numberOfArgument =len(sys.argv)
weblogic_username =''
weblogic_password = ''
weblogic_admin_server_host =''
weblogic_admin_server_port =''


if numberOfArgument == 5:
        weblogic_username = sys.argv[1]
        weblogic_password = sys.argv[2]
        weblogic_admin_server_host =sys.argv[3]
        weblogic_admin_server_port=sys.argv[4]
elif numberOfArgument <5:
        print " weblogic UserName, weblogic Password and weblogic host details are Mandatory like, defalutUser, passwordForDefaultUser, t3s://server.domainname:7001 ."
        weblogic_username = raw_input("Enter Weblogic user Name")
        weblogic_password = raw_input('Enter Weblogic user Password')
        weblogic_admin_server_host = raw_input('Enter Weblogic admin host ')
        weblogic_admin_server_port = raw_input('Enter Weblogic admin port')
#enfelif
#endIf
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top