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

44.5k views Asked by At

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?

9

There are 9 answers

6
Glenn Maynard On BEST ANSWER

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 80x25 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.

0
nosklo On

This is what I do:

if (collResv.repeatability is None or
        collResv.somethingElse):
    collResv.rejected = True
    collResv.rejectCompletely()
3
Oben Sonne On

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.

4
Blorgbeard On

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()
0
stderr On

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.

0
ronak On

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)
7
Reimund On

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

Oracle seem to agree, see page 6, indendation: https://www.oracle.com/technetwork/java/codeconventions-150003.pdf

0
eyquem On

In such a case, I would simply do:

if (collResv.repeatability is None or
    collResv.somethingElse):
    # do:
    collResv.rejected = True
    collResv.rejectCompletely()
0
mcote On

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".