862

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?

General Grievance
  • 4,555
  • 31
  • 31
  • 45
Eli Bendersky
  • 263,248
  • 89
  • 350
  • 412
  • 2
    If your editor uses the [pep8](https://pypi.python.org/pypi/pep8) Python package to detect when to warn about [PEP8](http://www.python.org/dev/peps/pep-0008/) violations, you'll have to either disable the E125 error or find a formatting solution which satisfies the `pep8` package's criteria. The `pep8` package's [issue #126](https://github.com/jcrocholl/pep8/issues/126) is about fixing the package to strictly follow the PEP8 spec. The discussion for the issue includes some style suggestions also seen here. – akaihola Oct 22 '13 at 06:22
  • 1
    Note that for the first example, pep8 will throw "E129 visually indented line with same indent as next logical line". – Taylor D. Edmiston Sep 06 '16 at 19:24

30 Answers30

963

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.

mardlin
  • 292
  • 2
  • 12
Harley Holcombe
  • 175,848
  • 15
  • 70
  • 63
  • 65
    Note that the trailing \ solutions are not recommended by PEP 8. One reason is that if a space is added by mistake after a \ it might not show in your editor, and the code becomes syntactically incorrect. – Eric O. Lebigot Jan 14 '11 at 10:26
  • 26
    This is wrong, the style guide says " 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." You can see this here: http://www.python.org/dev/peps/pep-0008/#maximum-line-length – joshcartme Jan 21 '13 at 21:54
  • 11
    @joshcartme The PEP changed at http://hg.python.org/peps/rev/7a48207aaab6 to explicitly discourage backslashes. I'll update the answer. – Harley Holcombe Jan 22 '13 at 00:36
  • 4
    Thanks, it's probably a good idea to update your examples too since they are now not recommended. I was trying to figure this out myself and was confused by the discrepancy between your answer and the style guide (hence my comment). I wasn't just trying to be pedantic. – joshcartme Jan 22 '13 at 20:03
  • 1
    I also prefer your final example except I place 'and/or' at beginning of the lines. Since in python land white space is so we don't use brackets for code blocks wrapping code in brackets is going again that and just looks ugly IMO; PEP 8 is only a recommendation which means you don't have to follow it. – Daniel Sokolowski Jul 18 '13 at 17:40
  • 1
    Is there something wrong if we align the `and`s with the `if` in the last example? – aandis Jan 22 '16 at 10:21
  • 11
    [PEP 8](https://www.python.org/dev/peps/pep-0008/#should-a-line-break-before-or-after-a-binary-operator) now discourages breaking after the `and` and `if` as well. – virtualxtc Sep 11 '18 at 01:46
  • 2
    As a style note, I feel conditionals are more readable when the `and` & `or` are proceeding the line rather than following the previous line. – Boris Yakubchik Sep 14 '18 at 18:35
146

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.

S.Lott
  • 384,516
  • 81
  • 508
  • 779
  • 6
    This is an interesting approach. Doesn't address the issue of long conditions though – Eli Bendersky Oct 08 '08 at 11:04
  • 25
    It's ok if you don't care about shortcircuiting. – Constantin Oct 09 '08 at 23:39
  • @Constantin: The point was extensible, not fast. For fast, this isn't ideal. – S.Lott Oct 10 '08 at 00:02
  • 71
    shortcirtuiting is not always about fast. While not good coding practice, you may have existing code like this: `if destroy_world and DestroyTheWorld() == world_is_destroyed: ...`. Great, now you just destroyed the world on accident. HOW COULD YOU? – Aaron Jan 28 '09 at 21:43
  • 12
    I'm surprised that this has so many upvotes. This answer completely ignores the original question about styling *multi-line* conditionals. – Przemek D May 29 '18 at 06:09
  • 2
    This expression is not lazy. So it's not equivalent if some guarding condition are being followed by possibly failing one. – eugene-bright Aug 05 '18 at 22:35
72

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()
gitaarik
  • 42,736
  • 12
  • 98
  • 105
Deestan
  • 16,738
  • 4
  • 32
  • 48
  • 7
    +1 for keeping indents where you can keep track of them. I like python and use it a lot, but I'm constantly annoyed by being forced to indent just so. The multi-line if really destroys the aesthetic, even when done well. – mightypile Dec 22 '13 at 23:15
  • 6
    Note that having your `and` and `or` operators at the start of the line violates [PEP 0008](https://www.python.org/dev/peps/pep-0008/), which states *"The preferred place to break around a binary operator is after the operator, not before it."*. I like having the closing bracket and colon on their own line to separate the if condition from the body, though (and it's perfectly possible to do this while keeping your boolean operators at the end of the line for PEP-0008 compliance). – Mark Amery Jul 05 '15 at 14:24
  • 31
    as of 2016: `For decades the recommended style was to break after binary operators. But this can hurt readability in two ways`...`In Python code, it is permissible to break before or after a binary operator, as long as the convention is consistent locally. For new code Knuth's style is suggested.` (Knuth's style is start the line with operator). – cowbert Jan 11 '18 at 20:14
65

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.

Kevin Little
  • 12,436
  • 5
  • 39
  • 47
  • 22
    This doesn't seem to be beautiful nor PEP8-compatible. PEP8 says that the preferred place to break around a binary operator (e.g `and` as well as `or`) is _after_ the operator, not before it. – Chris Medrela Oct 25 '13 at 17:25
  • 12
    @ChristopherMedrela does it tell the rationale behind that? i think placing a line break before logic operator is a lot clearer – Norill Tempest May 08 '14 at 23:35
  • I much prefer this to the PEP8 version. I suppose there's an element of personal taste. – Michael Bylstra Aug 14 '14 at 00:25
  • 4
    Putting the oprerator first is quite common in the world of node. The rationale is that we notice and read stuff on the left a lot faster than stuff on the right — at least in the western cultures. Very valid in JavaScript, where a forgotten comma can cause silent errors. – tomekwi Oct 20 '14 at 08:30
  • 11
    Don't do this please. Not only is it not `PEP8` but makes it harder to determine the logic operation that you are chaining with. I would flunk this if it came to my desk through code review. – Urda Mar 04 '15 at 17:56
  • 7
    @Urda I disagree. Placing the binary operators at the beginning of lines instead of at the end IMO makes it clearer what the intent is. In the second example above, I think it's clear that the operands to `and` are combined together before before being `or`ed with the first condition. But maybe I think so because I like Lisp... – jamesdlin Aug 13 '15 at 12:39
  • 14
    As of the current version of PEP8, breaking either before or after a binary operator [is considered acceptable](http://legacy.python.org/dev/peps/pep-0008/#should-a-line-break-before-or-after-a-binary-operator), and before the operator is considered better for new code. – Soren Bjornstad Nov 11 '16 at 03:16
  • 2
    I like this answer the best because *The Zen of Python* `Readability counts.` `Special cases aren't special enough to break the rules.` `Although practicality beats purity.` https://www.python.org/dev/peps/pep-0020/ – JayRizzo May 30 '18 at 06:30
30

This doesn't improve so much but...

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

if allCondsAreOK:
   do_something
Federico A. Ramponi
  • 46,145
  • 29
  • 109
  • 133
  • 1
    Interesting alternative. But 2 extra lines :-) – Eli Bendersky Oct 08 '08 at 06:37
  • Wouldnt really work that well in an iterative loop, wouldnt work with functions doing something... and to be fair - ugly – Mez Oct 08 '08 at 06:37
  • If you're only going to use a variable once, I'd prefer not to use a variable at all. – Brian Oct 08 '08 at 07:48
  • 11
    brian, I partly disagree. Using variables for intermediate results of a calculation can make code easier to understand, and in a compiled language won't have any performance impact. It probably would do in python, though I wouldn't use python at all if perfomance was that important. – Mark Baker Oct 08 '08 at 09:00
  • 2
    @MarkBaker I used to agree with what you wrote, until I read Martin Fowlers "Refactoring". He provides an excellent argument that such intermediate variables cause more harm than benefit. They inhibit subsequent refactoring. Doing without them leads to a more functional programming style, which lends itself well to refactoring. This surprised me, but I believe he's right, and have since striven to eliminate needless intermediates like this from my code - even if they are used more than once. – Jonathan Hartley Oct 09 '12 at 12:32
  • 1
    Also, I'll take this opportunity to state that using a slow programming language (e.g. Python) does not cause application performance problems. In the six years since I switched from C++ and C# to Python, I haven't found my code suffers from any more performance problems. When it does, this turns out to be due to bad algorithm choices or IO. Only once in that whole time have I found Python performance to be lacking in any way that mattered - while morphing meshes of vertices every frame before sending them to OpenGL. In that case the correct & obvious solutions (use Numpy or shaders) fixed it. – Jonathan Hartley Oct 09 '12 at 12:37
  • This is the most expressive and it lays out naturally. Usually there would be a nice meaningful name to assign to the conditionals which will aid quick comprehension when you come back to the code in a year's time. I refactor a lot and having complex conditionals meaningfully 'labelled' with a variable name is very useful. – Paul Whipp Oct 27 '12 at 06:26
  • 3
    Good, but why camelCase?! :) – Leonid Shvechikov Mar 17 '13 at 17:37
  • @LeonidShvechikov Why not camelCase? – CatShoes Jun 11 '13 at 12:07
28

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.

Luke H
  • 87
  • 1
  • 7
krawyoti
  • 19,695
  • 1
  • 23
  • 17
19

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.

Dzinx
  • 55,586
  • 10
  • 60
  • 78
  • 10
    I read somewhere in either Gries or Djikstra that putting the logic operator at the front of the line -- making more visible -- helped. And I've been doing that since the 90's. And it helps. – S.Lott Oct 08 '08 at 10:23
  • 7
    Note that the Style Guide recommends putting the conditional at the end of the line. – Harley Holcombe Oct 09 '08 at 22:55
  • 3
    That's true, although I never agreed with it on this. It's only a guide, after all. – Dzinx Oct 10 '08 at 08:56
  • 10
    PEP8 [no longer recommends](http://legacy.python.org/dev/peps/pep-0008/#should-a-line-break-before-or-after-a-binary-operator) putting the conditional at the end of the line. – Soren Bjornstad Nov 11 '16 at 03:16
17

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.

Mark Amery
  • 143,130
  • 81
  • 406
  • 459
  • +1 for PEP8. This _ought_ to be accepted, since it is (practically speaking) the official Python style guide. – Michael Jun 14 '16 at 14:29
  • 3
    Also worth emphasizing that, PEP8 explicitly states its stance as **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: ... (snipped)** So, stop argueing, go with something you like! – RayLuo Sep 14 '16 at 02:22
8

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
zkanda
  • 714
  • 1
  • 6
  • 5
  • 1
    Bad case if in `cond4` you wanna check the function or if `cond2` is a property of `cond1`. Example conditions: ```object is not None and object.param == 5 and object.is_running()``` – Oleg Mar 04 '21 at 08:29
  • At this point, why not just `condition = cond1 == 'val1' and cond2 == 'val2' ...`? Clearer (no separation of logical operator and conditions) and preserves short-circuiting behavior. – kdb May 31 '21 at 14:07
6

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

rgenito
  • 1,751
  • 13
  • 8
5

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

Community
  • 1
  • 1
ThorSummoner
  • 16,657
  • 15
  • 135
  • 147
  • 1
    I should also point out that pylint's stock configuration wants an entra indent on line continuation in an if; which has dissuaded me from using this scheme. – ThorSummoner Dec 02 '16 at 19:38
5

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.

Apalala
  • 9,017
  • 3
  • 30
  • 48
  • 1
    In addition to this you can declare a function or a lambda to return your true false as opposed to creating an extra variable. – Techdragon May 05 '13 at 14:42
  • @Techdragon if the conditions are to be elsewhere, then putting them into a lambda block would require the lambda block to be named so it can referenced later in the if condition. If a lambda is going to be named, why it and not a regular function after all? I personally like this reduced boolean expression. – Sri Kadimisetty Sep 01 '13 at 09:58
  • I agree, which is why I would normally use a function in most cases for both improved readability and ease of mental digestion when skimming to understand program control flow. I mention the lambda to ensure that the 'smaller' option is also present in case people are particularly space conscious. – Techdragon Sep 13 '13 at 01:24
  • This is cool. Unfortunately if I include `Path(input).is_dir()` or `Path(input).is_file()` into the variable clause, I receive `TypeError: 'bool' object is not callable`. – howdoicode Sep 30 '20 at 15:57
4

(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
}
Fred Nurk
  • 13,952
  • 4
  • 37
  • 63
4

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.

Marius Gedminas
  • 11,010
  • 4
  • 41
  • 39
3

"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
Anders Waldenborg
  • 2,955
  • 1
  • 22
  • 24
  • 5
    Incorrect! They only do because *you* do. Try all(f() for f in [c1, c2]). – habnabit Jan 27 '09 at 05:39
  • 2
    I think he was using functions only as an example, because he can easily make them print something. If we are considering a series of arbitrary expressions supplied in a list to `all()` then, unless you are going to wrap them each in a lambda and use your `f()` trick, they are all going to get evaluated. In other words, Aaron: I think Anders was trying to talk about conditions in general, using callables as a specific example; but your rejoinder applies only to functions. – Brandon Rhodes Jan 16 '11 at 06:04
3

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
ryanjdillon
  • 17,658
  • 9
  • 85
  • 110
2

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

Federico A. Ramponi
  • 46,145
  • 29
  • 109
  • 133
  • 3
    This would be very confusing, especially when the body of the conditional is long, I think. – Eli Bendersky Oct 09 '08 at 05:52
  • I agree with Eli, the encapsulation and indentation here is confusing for long lines. Moreover, [the new rule](https://www.python.org/dev/peps/pep-0008/#should-a-line-break-before-or-after-a-binary-operator) is that the `and` and `or` statements should start on the next line – virtualxtc Sep 11 '18 at 01:57
2

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.

tomekwi
  • 2,048
  • 2
  • 21
  • 27
  • 1
    Almost correct; [PEP 8](https://www.python.org/dev/peps/pep-0008/#should-a-line-break-before-or-after-a-binary-operator) now recommends breaking before the `and` or `or`. – virtualxtc Sep 11 '18 at 01:52
2

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

SMGreenfield
  • 1,680
  • 19
  • 35
  • This is a poor design AFAIK. I mean we should think again about our code if we have to do this kind of coding. TBH I have the same problem. I came from a Node.js background, in that dimension we do not care about this problem, to be direct it is not a problem at all. In node.js we have prettier. BTW I guess in those situation we should transmute our dogmatic belief if we have one. – Kasir Barati Jun 28 '22 at 13:08
2

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.

Stof
  • 610
  • 7
  • 16
  • this is indeed a very neat way of doing multi-conditionals :) don't know why it does not have more votes :), are there any caveats? – dim_user Mar 06 '18 at 20:09
  • @SaulCruz there really isn't Not only does the condition variable not need to be repeated you also save on the many duplicates of checking each value, this simply puts only the values in an array and let the engine do it's (optimized) job in checking the condition for you – Stof Mar 12 '18 at 13:19
  • 1
    @Stoff Thank you for removing my comment. I wanted to point out that your approach does not answer the OP's question. The code you provide cannot be applied to the code in the question. If you think otherwise then you should add OP's code reformatted by your approach to prove your point. – Jeyekomon Jun 06 '18 at 09:11
  • It is not the accepted answer however it is clearly an alternative approach (others agree). SO encouraged alternative answers so what’s the argument exactly? Be clear in your own question, perhaps consider opening your own question if you require the proper attention. P.s. I am not an SO mod, I cannot remove comments – Stof Jun 06 '18 at 09:14
1

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

Jason Baker
  • 192,085
  • 135
  • 376
  • 510
1

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

El Ninja Trepador
  • 1,013
  • 1
  • 10
  • 14
1

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.

SarcasticSully
  • 442
  • 4
  • 14
1

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

Nader Belal
  • 157
  • 3
  • 10
0

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"')
user1487551
  • 391
  • 2
  • 3
  • 8
0

I usually use:

if ((cond1 == 'val1' and cond2 == 'val2' and
     cond3 == 'val3' and cond4 == 'val4')):
    do_something()
Artur Gaspar
  • 4,407
  • 1
  • 26
  • 28
0

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

if False not in Conditions:
    do_something
psihodelia
  • 29,566
  • 35
  • 108
  • 157
0

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
Gautam
  • 3,707
  • 5
  • 36
  • 57
0

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
xorsyst
  • 7,897
  • 5
  • 39
  • 58
  • 1
    @qarma, would you care to expand? It's surely better than using line-continuation characters, which are recommended against by PEP 8 – xorsyst Mar 13 '12 at 14:27
  • This is in fact a valid case for line continuation. IMPO Parentheses signify a tuple or a function call. OP's use is very C-like, I prefer python syntax whenever possible. I concede that \ is not universally favoured though. – Dima Tisnek Mar 14 '12 at 11:13
0
  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

Dima Tisnek
  • 11,241
  • 4
  • 68
  • 120
  • Google's guide also provides [an example of a complex condition](http://google-styleguide.googlecode.com/svn/trunk/pyguide.html?showone=Line_length#Line_length), which matches “the most obvious way to do this” as mentioned by the OP. Although the guide doesn't explicitly advocate formatting long “if”s that way. – Anton Strogonoff Apr 08 '12 at 10:05