Укладка многострочных условий в выражениях "если"?

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

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

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

Ответ 1

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

Ответ 2

Я применил следующее в вырожденном случае, где он просто И или ИЛИ.

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

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

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

Ответ 3

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

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

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

Ответ 4

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

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

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

Ответ 5

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

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

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

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

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

Ответ 6

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

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

if allCondsAreOK:
   do_something

Ответ 7

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

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

Ответ 8

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

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

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

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

Ответ 9

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

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

Так как and - это ключевое слово, оно подсвечивается моим редактором и выглядит достаточно отличным от do_something под ним.

Ответ 10

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

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

if all(condition):
   do_something

Ответ 11

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

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

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

Ответ 12

Обычный и простой, также проходит проверки pep8:

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

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

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

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

Примечание: any соответствует многим сравнениям or, all соответствует многим сравнениям 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!")

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

Ответ 13

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

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

Ответ 14

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

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

    do_something

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

Ответ 15

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

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

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

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

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

Ответ 16

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

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

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

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

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

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

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

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

Ответ 17

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

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

>>> 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'

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

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

Ответ 18

Я обычно делаю:

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

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

Ответ 19

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

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

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

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

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

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

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

Ответ 20

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

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

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

Ответ 21

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

if False not in Conditions:
    do_something

Ответ 22

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

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

Ответ 23

  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

Ответ 24

Здесь другой подход:

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"')

Ответ 25

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

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

Ответ 26

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

Ответ 27

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

Ответ 28

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

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

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

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

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

Ответ 29

Я думаю, что решение @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 operator:

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

if proceed:
    # do something