it-roy-ru.com

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

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

  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

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

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

530
Eli Bendersky

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

576
Harley Holcombe

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

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

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

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

105
S.Lott

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

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

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

48
Kevin Little

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

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

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

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

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

23
krawyoti

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

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

if allCondsAreOK:
   do_something
21
Federico A. Ramponi

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

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

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

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

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

19
DzinX

Кажется, стоит цитировать 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()

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

10
Mark Amery

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

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

if all(condition):
   do_something
5
zkanda

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

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

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

4
Marius Gedminas

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

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

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

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

3
rgenito

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

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

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

3
Apalala

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

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
3
Anders Waldenborg

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

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
}
3
Fred Nurk

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

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

В последнее время я предпочел функции all и any, так как я редко смешиваю сравнения And и Or, это работает хорошо, и имеет дополнительное преимущество Failing 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!")

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

3
ThorSummoner

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

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

    do_something

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

2
Federico A. Ramponi

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

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

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

1
tomekwi

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

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

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

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

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

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

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

1
El Ninja Trepador

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

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

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

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

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

1
Jason Baker

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

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

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

1
SarcasticSully

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

1
SMGreenfield

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

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

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

#!/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
0
Laxman G

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

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

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

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

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

if False not in Conditions:
    do_something
0
psihodelia

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

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

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

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

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

0
Stoff

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

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

Я думаю, что-то вроде этого является наиболее читаемым вариантом:

for pet in Zoo:
    cute = every_pet()
    furry = hair is 'over9000'
    small = size < min_size
    if cute and furry and small:
        return 'I need to feed it!'
0
Alex
  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

0
Dima Tisnek