Стилизировать многострочные условия в операторах 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 ]

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

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

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

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

3 голосов
/ 24 ноября 2014

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

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

В последнее время я предпочел функции all и any, так как я редко смешиваю сравнения «И» и «Или», это хорошо работает и имеет дополнительное преимущество - «Неудачный ранний» с пониманием генераторов:

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 голосов
/ 08 октября 2008

«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 голосов
/ 19 января 2011

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

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

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

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

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

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
}
2 голосов
/ 09 октября 2008

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

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

    do_something

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

1 голос
/ 01 августа 2014

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

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

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

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

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

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

>>> 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 голос
/ 21 июля 2017

Я думаю, что решение @ 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 голос
/ 29 ноября 2016

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

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