Multiline If statement with a single conditional

Viewed 1576

Lets say I have two variables

self.SuperLongSpecificCorperateVariableNameIcantChangeCommunication 

and

self.SuperLongSpecificCorperateVariableNameIcantChangeControl 

And I need to compare them.

The issue being that, when I put them both in an if statement, it blows past the style checker's line length.

if (self.SuperLongSpecificCorperateVariableNameIcantChangeCommunication != self.SuperLongSpecificCorperateVariableNameIcantChangeControl):

The way around this would be to split this into two lines.

if (self.SuperLongSpecificCorperateVariableNameIcantChangeCommunication \
    != self.SuperLongSpecificCorperateVariableNameIcantChangeControl):

My coworkers are split on whether PEP 8 has you split between conditionals or whether you can split up a conditional itself. Ideally we would get approval to change the variable name, but in the meantime, what does PEP 8 say we should do in this case?

2 Answers

According to PEP8:

The preferred way of wrapping long lines is by using Python's implied line continuation inside parentheses, brackets and braces. Long lines can be broken over multiple lines by wrapping expressions in parentheses. These should be used in preference to using a backslash for line continuation.

There is also a discussion about multiline if-statements which doesn't take an explicit position but recommends to add an indentation level to the conditional's continuation line.

Lastly, Should a Line Break Before or After a Binary Operator? recommends to break before the operator (as you did). So you could write:

if (self.SuperLongSpecificCorperateVariableNameIcantChangeCommunication
        != self.SuperLongSpecificCorperateVariableNameIcantChangeControl):
    pass

But variables in Python are just names - a way to reference an object. Names can be changed. Line breaks can be avoided:

communication = self.SuperLongSpecificCorperateVariableNameIcantChangeCommunication 
control = self.SuperLongSpecificCorperateVariableNameIcantChangeControl 

if communication != control:
    pass

Firstly, PEP 8 says you can split long lines under Maximum Line Length:

Long lines can be broken over multiple lines by wrapping expressions in parentheses. These should be used in preference to using a backslash for line continuation.

In fact, the backslash in your example is not needed because of the parentheses.


PEP 8 says you can split a conditional under multiline if-statements, although the main focus of that section is how to distinguish it from the following block.

When the conditional part of an if-statement is long enough to require that it be written across multiple lines, it's worth noting that the combination of a two character keyword (i.e. if), plus a single space, plus an opening parenthesis creates a natural 4-space indent for the subsequent lines of the multiline conditional. This can produce a visual conflict with the indented suite of code nested inside the if-statement, which would also naturally be indented to 4 spaces. This PEP takes no explicit position on how (or whether) to further visually distinguish such conditional lines from the nested suite inside the if-statement. Acceptable options in this situation include, but are not limited to:

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

Personally, I would go for the last option for maximum readability. So that gives us:

if (self.SuperLongSpecificCorperateVariableNameIcantChangeCommunication
        != self.SuperLongSpecificCorperateVariableNameIcantChangeControl):
    do_something()

Other options

You could use temporary "internal use" names to shorten the line:

_Comm = self.SuperLongSpecificCorperateVariableNameIcantChangeCommunication
_Control = self.SuperLongSpecificCorperateVariableNameIcantChangeControl
if _Comm != _Control:
    do_something()

This is assuming the context is not in a local scope. If it is actually in a local scope, they don't need to be "internal use".


You could use a helper function to give them shorter names in a local scope. Since they're attributes, you can pass in their object:

def _compare(instance):
    a = instance.SuperLongSpecificCorperateVariableNameIcantChangeCommunication
    b = instance.SuperLongSpecificCorperateVariableNameIcantChangeControl
    return a != b

if _compare(self):
    do_something()
Related