Стиль многострочных условий в операторах "if"?

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


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


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

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

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


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

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

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


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

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

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

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

С and является ключевым словом, оно выделяется моим редактором и выглядит достаточно отличным от do_something ниже него.


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

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

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

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 петли, затем с помощью локальной функции лучший.


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

английский: "если вошедший в систему пользователь не является учителем администратора, а просто обычным учителем, и не является учеником..."

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

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

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

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

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

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


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

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

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

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

просто не забудьте пройти в одном iterable! Передача N-аргументов не является правильной.

Примечание: any как много or сравнения all is как многие and сравнения.


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

# 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!"

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

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


упакуйте свои условия в список, затем сделайте smth. например:

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.com/svn/trunk/pyguide.html?showone=Indentation#Indentation


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

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 & an else должно выполнить несколько операторов внутри него, чем мы можем написать, как показано ниже. Каждый раз, когда у нас есть пример if 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

все респонденты, которые также предоставляют multi-conditionals для оператора 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