Code-style for indention of multi-line 'if' statement?

Question:

When indenting long if conditions, you usually do something like this (actually, PyDev indents like that):

if (collResv.repeatability is None or
    collResv.somethingElse):
    collResv.rejected = True
    collResv.rejectCompletely()

However, this puts the block started by the if statement on the same indentation level as the last part of the if condition which makes it very ugly/hard to read in my opinion as you don’t immediately see where the block starts.

Some other styles I thought about:

if (collResv.repeatability is None or
        collResv.somethingElse):
    collResv.rejected = True
    collResv.rejectCompletely()

This looks pretty inconsistent as the second line is indented much more than the first line but it’s readable.

if (collResv.repeatability is None or
  collResv.somethingElse):
    collResv.rejected = True
    collResv.rejectCompletely()

This is also more readable than the first example, but the indentation is not a multiple of 4 anymore and besides that it looks wrong as the second line has less indentation than the beginning of the condition in the first line.


So, my main question is: Is there a suggested indentation style for cases like that which do not require overly-long lines (i.e. a single-line condition)?
If not, what do you prefer for cases like that?

Asked By: ThiefMaster

||

Answers:

This is what I do:

if (collResv.repeatability is None or
        collResv.somethingElse):
    collResv.rejected = True
    collResv.rejectCompletely()
Answered By: nosklo

Often I work around this problem by calculating the condition in an own statement:

condition = (collResv.repeatability is None or
             collResv.somethingElse)
if condition:
    collResv.rejected = True
    collResv.rejectCompletely()

Though, for a still relatively short condition as in your specific example I’d go for nosklo‘s solution – the extra statement used here is more suited for even longer conditional expressions.

Answered By: Oben Sonne

This is an indirect answer–not answering the style question directly, but it’s the practical answer in general, so it’s worth mentioning.

I find it extremely rare to need to write multi-line conditionals. There are two factors to this:

  • Don’t wrap code at 80 columns. PEP-8’s advice on this subject is ancient and harmful; we’re well past the days of 80×25 terminals and editors that can’t sensibly handle wrapping. 100 columns is fine, and 120 is usually acceptable, too.
  • If conditions become so long that they still need to wrap, it’s usually reasonable to move some of the logic out of the conditional and into a separate expression. This also tends to help readability.

Grepping through my recent projects, around 12kloc, there’s only one conditional long enough that it needed to be wrapped; the issue simply very rarely arises. If you do need to do this, then as nosklo says, indent it separately–as you noticed, indenting it to the same level as the block beneath it is confusing and hard to read.

Answered By: Glenn Maynard

An option I sometimes use (although I’m not completely sold on its readability):

if (collResv.repeatability is None or
    collResv.somethingElse
):
    collResv.rejected = True
    collResv.rejectCompletely()

Possibly it would be more readable this way:

if (
collResv.repeatability is None or
collResv.somethingElse
):
    collResv.rejected = True
    collResv.rejectCompletely()
Answered By: Blorgbeard

Pep-8 recommends the way you indented your original example.

Now if you’re willing to fly in the face of the oh so sacred of style guides 🙂 you could move the operator to the next line:

if (collResv.repeatability is None
    or collResv.somethingElse):
    collResv.rejected = True
    collResv.rejectCompletely()

I’m not really a fan of this, I actually find your original syntax fairly easy to read and wouldn’t spend much time monkeying with the indentation or line breaks.

Answered By: stderr

In such a case, I would simply do:

if (collResv.repeatability is None or
    collResv.somethingElse):
    # do:
    collResv.rejected = True
    collResv.rejectCompletely()
Answered By: eyquem

I would do it this way. Keep it indented far away not to get confused.

if (collResv.repeatability is None or
                          collResv.somethingElse):
    collResv.rejected = True
    collResv.rejectCompletely()

PEP-8 advise is right here.

http://www.python.org/dev/peps/pep-0008/#indentation

Below code is advised

# Aligned with opening delimiter
foo = long_function_name(var_one, var_two,
                         var_three, var_four)

# More indentation included to distinguish this from the rest.
def long_function_name(
        var_one, var_two, var_three,
        var_four):
    print(var_one)

Below code is not advised

# Arguments on first line forbidden when not using vertical alignment
foo = long_function_name(var_one, var_two,
    var_three, var_four)

# Further indentation required as indentation is not distinguishable
def long_function_name(
    var_one, var_two, var_three,
    var_four):
    print(var_one)
Answered By: ronak

One problem with all previous suggestions here is that the logical operators for the subsequent conditions are put on the preceding line. Imo, that makes it less readable.

I recommend putting the logical operator on the same line as the condition it appends to the if statement.

This in my opinion, is better

if (None == foo
        and None == bar
        or None == foo_bar):

than this:

if (None == foo and
        None == bar or
        None == foo_bar):
Answered By: Reimund

PEP-8 actually seems contradictory here. While the example under “Maximum Line Length” shows the use of parentheses and a standard 4-character indent, the “Indentation” section says, with respect to function declarations, “further indentation should be used to clearly distinguish itself as a continuation line.”. I don’t see why this would be restricted only to “def” and not to “if”.

Answered By: mcote