Styling multi-line conditions in 'if' statements? [closed]

Sometimes I break long conditions in ifs onto several lines. The most obvious way to do this is:

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

Isn't very very appealing visually, because the action blends with the conditions. However, it is the natural way using correct Python indentation of 4 spaces.

For the moment I'm using:

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

But this isn't very pretty. :-)

Can you recommend an alternative way?


Asked by: Ted521 | Posted: 01-10-2021






Answer 1

You don't need to use 4 spaces on your second conditional line. Maybe use:

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

Also, don't forget the whitespace is more flexible than you might think:

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

Both of those are fairly ugly though.

Maybe lose the brackets (the Style Guide discourages this though)?

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

This at least gives you some differentiation.

Or even:

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

I think I prefer:

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

Here's the Style Guide, which (since 2010) recommends using brackets.

Answered by: Freddie720 | Posted: 02-11-2021



Answer 2

I've resorted to the following in the degenerate case where it's simply AND's or OR's.

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

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

It shaves a few characters and makes it clear that there's no subtlety to the condition.

Answered by: Dainton628 | Posted: 02-11-2021



Answer 3

Someone has to champion use of vertical whitespace here! :)

if (     cond1 == val1
     and cond2 == val2
     and cond3 == val3
   ):
    do_stuff()

This makes each condition clearly visible. It also allows cleaner expression of more complex conditions:

if (    cond1 == val1
     or 
        (     cond2_1 == val2_1
          and cond2_2 >= val2_2
          and cond2_3 != bad2_3
        )
   ):
    do_more_stuff()

Yes, we're trading off a bit of vertical real estate for clarity. Well worth it IMO.

Answered by: Catherine548 | Posted: 02-11-2021



Answer 4

I prefer this style when I have a terribly large if-condition:

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

Answered by: Charlie758 | Posted: 02-11-2021



Answer 5

This doesn't improve so much but...

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

if allCondsAreOK:
   do_something

Answered by: Catherine976 | Posted: 02-11-2021



Answer 6

Here's my very personal take: long conditions are (in my view) a code smell that suggests refactoring into a boolean-returning function/method. For example:

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

Now, if I found a way to make multi-line conditions look good, I would probably find myself content with having them and skip the refactoring.

On the other hand, having them perturb my aesthetic sense acts as an incentive for refactoring.

My conclusion, therefore, is that multiple line conditions should look ugly and this is an incentive to avoid them.

Answered by: Rubie133 | Posted: 02-11-2021



Answer 7

I suggest moving the and keyword to the second line and indenting all lines containing conditions with two spaces instead of four:

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

This is exactly how I solve this problem in my code. Having a keyword as the first word in the line makes the condition a lot more readable, and reducing the number of spaces further distinguishes condition from action.

Answered by: Edgar990 | Posted: 02-11-2021



Answer 8

It seems worth quoting PEP 0008 (Python's official style guide), since it comments upon this issue at modest length:

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

Note the "not limited to" in the quote above; besides the approaches suggested in the style guide, some of the ones suggested in other answers to this question are acceptable too.

Answered by: Sawyer766 | Posted: 02-11-2021



Answer 9

Here's what I do, remember that "all" and "any" accepts an iterable, so I just put a long condition in a list and let "all" do the work.

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

if all(condition):
   do_something

Answered by: Owen877 | Posted: 02-11-2021



Answer 10

Personally, I like to add meaning to long if-statements. I would have to search through code to find an appropriate example, but here's the first example that comes to mind: let's say I happen to run into some quirky logic where I want to display a certain page depending on many variables.

English: "If the logged-in user is NOT an administrator teacher, but is just a regular teacher, and is not a student themselves..."

if not user.isAdmin() and user.isTeacher() and not user.isStudent():
    doSomething()

Sure this might look fine, but reading those if statements is a lot of work. How about we assign the logic to label that makes sense. The "label" is actually the variable name:

displayTeacherPanel = not user.isAdmin() and user.isTeacher() and not user.isStudent()
if displayTeacherPanel:
    showTeacherPanel()

This may seem silly, but you might have yet another condition where you ONLY want to display another item if, and only if, you're displaying the teacher panel OR if the user has access to that other specific panel by default:

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

Try writing the above condition without using variables to store and label your logic, and not only do you end up with a very messy, hard-to-read logical statement, but you also just repeated yourself. While there are reasonable exceptions, remember: Don't Repeat Yourself (DRY).

Answered by: Emily881 | Posted: 02-11-2021



Answer 11

Adding to what @krawyoti said... Long conditions smell because they are difficult to read and difficult to understand. Using a function or a variable makes the code clearer. In Python, I prefer to use vertical space, enclose parenthesis, and place the logical operators at the beginning of each line so the expressions don't look like "floating".

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

If the conditions need to be evaluated more than once, as in a while loop, then using a local function is best.

Answered by: Maya625 | Posted: 02-11-2021



Answer 12

Plain and simple, also passes pep8 checks:

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

In recent times I have been preferring the all and any functions, since I rarely mix And and Or comparisons this works well, and has the additional advantage of Failing Early with generators comprehension:

if all([
    cond1,
    cond2,
]):
    print("Hello World!")

Just remember to pass in a single iterable! Passing in N-arguments is not correct.

Note: any is like many or comparisons, all is like many and comparisons.


This combines nicely with generator comprehensions, for example:

# 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!")

More on: generator comprehension

Answered by: Richard150 | Posted: 02-11-2021



Answer 13

(I've lightly modified the identifiers as fixed-width names aren't representative of real code – at least not real code that I encounter – and will belie an example's readability.)

if (cond1 == "val1" and cond22 == "val2"
and cond333 == "val3" and cond4444 == "val4"):
    do_something

This works well for "and" and "or" (it's important that they're first on the second line), but much less so for other long conditions. Fortunately, the former seem to be the more common case while the latter are often easily rewritten with a temporary variable. (It's usually not hard, but it can be difficult or much less obvious/readable to preserve the short-circuiting of "and"/"or" when rewriting.)

Since I found this question from your blog post about C++, I'll include that my C++ style is identical:

if (cond1 == "val1" and cond22 == "val2"
and cond333 == "val3" and cond4444 == "val4") {
    do_something
}

Answered by: Lenny711 | Posted: 02-11-2021



Answer 14

I'm surprised not to see my preferred solution,

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

Since and is a keyword, it gets highlighted by my editor, and looks sufficiently different from the do_something below it.

Answered by: Charlie485 | Posted: 02-11-2021



Answer 15

"all" and "any" are nice for the many conditions of same type case. BUT they always evaluates all conditions. As shown in this example:

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

Answered by: Stella642 | Posted: 02-11-2021



Answer 16

What if we only insert an additional blank line between the condition and the body and do the rest in the canonical way?

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

    do_something

p.s. I always use tabs, not spaces; I cannot fine-tune...

Answered by: William247 | Posted: 02-11-2021



Answer 17

What I usually do is:

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

this way the closing brace and colon visually mark the end of our condition.

Answered by: Elian966 | Posted: 02-11-2021



Answer 18

I know this thread is old, but I have some Python 2.7 code and PyCharm (4.5) still complains about this case:

if foo is not None:
    if (cond1 == 'val1' and cond2 == 'val2' and
        cond3 == 'val3' and cond4 == 'val4'):
            # some comment about do_something
            do_something

Even with the PEP8 warning "visually indented line with same indent as next logical line", the actual code is completely OK? It's not "over-indenting?"

...there are times I wish Python would've bit the bullet and just gone with curly braces. I wonder how many bugs have been accidentally introduced over the years due to accidental mis-indentation...

Answered by: Alford457 | Posted: 02-11-2021



Answer 19

All respondents that also provide multi-conditionals for the if statement is just as ugly as the problem presented. You don't solve this problem by doing the same thing..

Even the PEP 0008 answer is repulsive.

Here is a far more readable approach

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

Want me to eat my words? Convince me you need multi-conditionals and I'll literally print this and eat it for your amusement.

Answered by: Brooke165 | Posted: 02-11-2021



Answer 20

I think @zkanda's solution would be good with a minor twist. If you had your conditions and values in their own respective lists, you could use a list comprehension to do the comparison, which would make things a bit more general for adding condition/value pairs.

conditions = [1, 2, 3, 4]
values = [1, 2, 3, 4]
if all([c==v for c, v in zip(conditions, values)]):
    # do something

If I did want to hard-code a statement like this, I would write it like this for legibility:

if (condition1==value1) and (condition2==value2) and \
   (condition3==value3) and (condition4==value4):

And just to throw another solution out there with an iand operator:

proceed = True
for c, v in zip(conditions, values):
    proceed &= c==v

if proceed:
    # do something

Answered by: Chester610 | Posted: 02-11-2021



Answer 21

Just a few other random ideas for completeness's sake. If they work for you, use them. Otherwise, you're probably better off trying something else.

You could also do this with a dictionary:

>>> x = {'cond1' : 'val1', 'cond2' : 'val2'}
>>> y = {'cond1' : 'val1', 'cond2' : 'val2'}
>>> x == y
True

This option is more complicated, but you may also find it useful:

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

Dunno if that works for you, but it's another option to consider. Here's one more way:

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'

The last two I haven't tested, but the concepts should be enough to get you going if that's what you want to go with.

(And for the record, if this is just a one time thing, you're probably just better off using the method you presented at first. If you're doing the comparison in lots of places, these methods may enhance readability enough to make you not feel so bad about the fact that they are kind of hacky.)

Answered by: Carina345 | Posted: 02-11-2021



Answer 22

I've been struggling to find a decent way to do this as well, so I just came up with an idea (not a silver bullet, since this is mainly a matter of taste).

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

I find a few merits in this solution compared to others I've seen, namely, you get exactly an extra 4 spaces of indentation (bool), allowing all conditions to line up vertically, and the body of the if statement can be indented in a clear(ish) way. This also keeps the benefits of short-circuit evaluation of boolean operators, but of course adds the overhead of a function call that basically does nothing. You could argue (validly) that any function returning its argument could be used here instead of bool, but like I said, it's just an idea and it's ultimately a matter of taste.

Funny enough, as I was writing this and thinking about the "problem", I came up with yet another idea, which removes the overhead of a function call. Why not indicate that we're about to enter a complex condition by using extra pairs of parentheses? Say, 2 more, to give a nice 2 space indent of the sub-conditions relative to the body of the if statement. Example:

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

I kind of like this because when you look at it, a bell immediatelly rings in your head saying "hey, there's a complex thing going on here!". Yes, I know that parentheses don't help readability, but these conditions should appear rarely enough, and when they do show up, you are going to have to stop and read them carefuly anyway (because they're complex).

Anyway, just two more proposals that I haven't seen here. Hope this helps someone :)

Answered by: Grace464 | Posted: 02-11-2021



Answer 23

You could split it into two lines

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

Or even add on one condition at a time. That way, at least it separates the clutter from the if.

Answered by: Maya99 | Posted: 02-11-2021



Answer 24

Pack your conditions into a list, then do smth. like:

if False not in Conditions:
    do_something

Answered by: Emily648 | Posted: 02-11-2021



Answer 25

I find that when I have long conditions, I often have a short code body. In that case, I just double-indent the body, thus:

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

Answered by: Kellan470 | Posted: 02-11-2021



Answer 26

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

or if this is clearer:

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

There is no reason indent should be a multiple of 4 in this case, e.g. see "Aligned with opening delimiter":

http://google-styleguide.googlecode.com/svn/trunk/pyguide.html?showone=Indentation#Indentation

Answered by: Sydney979 | Posted: 02-11-2021



Answer 27

Here's another approach:

cond_list = ['cond1 == "val1"','cond2=="val2"','cond3=="val3"','cond4=="val4"']
if all([eval(i) for i in cond_list]):
 do something

This also makes it easy to add another condition easily without changing the if statement by simply appending another condition to the list:

cond_list.append('cond5=="val5"')

Answered by: Melanie118 | Posted: 02-11-2021



Answer 28

I usually use:

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

Answered by: Lucas535 | Posted: 02-11-2021



Answer 29

if our if & an else condition has to execute multiple statement inside of it than we can write like below. Every when we have if else example with one statement inside of it .

Thanks it work for me.

#!/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

Answered by: Brad870 | Posted: 02-11-2021



Answer 30

Pardon my noobness, but it happens that I'm not as knowledgeable of #Python as anyone of you here, but it happens that I have found something similar when scripting my own objects in a 3D BIM modeling, so I will adapt my algorithm to that of python.

The problem that I find here, is double sided:

  1. Values my seem foreign for someone who may try to decipher the script.
  2. Code maintenance will come at a high cost, if those values are changed (most probable), or if new conditions must be added (broken schema)

Do to bypass all these problems, your script must go like this

param_Val01 = Value 01   #give a meaningful name for param_Val(i) preferable an integer
param_Val02 = Value 02
param_Val03 = Value 03
param_Val04 = Value 04   # and ... etc

conditions = 0           # this is a value placeholder

########
Add script that if true will make:

conditions = conditions + param_Val01   #value of placeholder is updated
########

### repeat as needed


if conditions = param_Val01 + param_Val02 + param_Val03 + param_Val04:
    do something

Pros of this method:

  1. Script is readable.

  2. Script can be easy maintained.

  3. conditions is a 1 comparison operation to a sum of values that represents the desired conditions.
  4. No need for multilevel conditions

Hope it help you all

Answered by: Elise691 | Posted: 02-11-2021



Similar questions

Multi-line regex with multiple matches and negative conditions in python

I am reading a text file and attempting to capture one of the arguments of each distinct tag, which has not been commented out. More specifically, I have the following input... maybe there is some text \THISTAG[arg1=1,argtwo]{WANT0} % \THISTAG[arg1=1,argtwo]{NOTWANT} % blah blah \THISTAG[arg1=1,argtwo]{NOTWANT} \THISTAG[arg1=1,argtwo]{WANT1}\THISTAG[arg1=1,argtwo]{WANT2}\\stuff \sometag{stuff I don'...


python - How can I generate multi-line build commands?

In SCons, my command generators create ridiculously long command lines. I'd like to be able to split these commands across multiple lines for readability in the build log. e.g. I have a SConscipt like: import os # create dependency def my_cmd_generator(source, target, env, for_signature): return r'''echo its a small world after all \ its a small world after all''' my_cmd_builder = Bu...


python - Replace each char in a multi-line string except space and \r \n, how?

A multi-line string, e.g. abc 123 456 def wanted result (ordinal + 2): cde 345 678 fgh if I use: text = "abc 123\n456 def" add2=''.join(chr(ord(c)+2) for c in text) print text print add2 the space and \r \n will also be replaced, how can I add the exception of not including space, \r or \n


regex - multi-line pattern matching in python

A periodic computer generated message (simplified): Hello user123, - (604)7080900 - 152 - minutes Regards Using python, how can I extract "(604)7080900", "152", "minutes" (i.e. any text following a leading "- " pattern) between the two empty lines (empty line is the \n\n after "Hello user123" and the \n\n before "Regards"). Even better if the result...


debugging - How to execute multi-line statements within Python's own debugger (PDB)

So I am running a Python script within which I am calling Python's debugger, PDB by writing: import ipdb; ipdb.set_trace() (iPython's version of PDB, though for the matter I don't think it makes a difference; I use it for the colored output only). Now, when I get to the debugger I want to execute a multi-line statement such as an if clause or a for loop but as soon as I type


Python multi-line strings breaks Vim's indent folding

Python's string-literal juxtaposition makes multi-line strings much easier and prettier to write, but when I'm four or five indents deep and want to use the entire row (leading whitespace does not matter), Vim's foldmethod=indent breaks down. For example: def getQuotation(): print "Fetching quotation from the absolutely useless function." ret...


python - Another Token error: EOF in multi-line statement

The following code gives me this error "Token Error: EOF in multi-line statement". I cannot seem to find the error though! Maybe someone else will see it? import easygui import time namegui = easygui.enterbox(msg='Enter your name:', title='Name query', default='Gian') situationgui = easygui.enterbox(msg='Please enter your situation:', title='Thought Log(Situation)') thoughtsgui = easygui.en...


python - Token error: EOF in multi-line statement

The following code gives me this error "Token Error: EOF in multi-line statement". What is this error? How can I fix it? import easygui import time namegui = easygui.enterbox(msg='Enter your name:', title='Name query', default='Gian') situationgui = easygui.enterbox(msg='Please enter your situation:', title='Thought Log(Situation)') thoughtsgui = easygui.enterbox(msg='Please enter your thou...


How Do I Read a Multi-line File of JSON and Count Words in Specific Field in Python

I have a file with many hundreds of lines of json encoded tweets pulled from python-tweetstreamer. The lines look like: {"favorited": false, "in_reply_to_user_id": null, "contributors": null, "truncated": false, "text": "kasian pak weking :| RT @veNikenD: Kasian kenapa???RT @SaputraJordhy: kasian \u256e(\u256f_\u2570)\u256d RT @veNikenD: Tak ingin lg kudengar kata2 yg tak ......", "created_at": "Tue Apr 03 ...


python - Paste Multi-line Snippets into IPython

I used IPython in the past and I used to be able to copy and paste multi-line commands, e.g., a for loop in IPython. Working in my new PC after installing Python(x,y) 2.7.2.1, I can paste multi-line snippets by using Right-click → Edit → Paste but not by using CTRL+P, as I used to do. When using CTRL+P only the first line for the multi-line snippet gets past...


python - Parse multi-line string up until first line with certain character

I want to parse out all lines from a multi-line string up until the first line which contains an certain character- in this case an opening bracket. s = """Here are the lines of text that i want. The first line with &lt;tags&gt; and everything after should be stripped.""" s1 = s[:s.find('&lt;')] s2 = s1[:s.rfind('\n')] print s2 Result: Here are ...






Still can't find your answer? Check out these communities...



PySlackers | Full Stack Python | NHS Python | Pythonist Cafe | Hacker Earth | Discord Python



top