How to exit an if clause
Asked Answered
A

15

159

What sorts of methods exist for prematurely exiting an if clause?

There are times when I'm writing code and want to put a break statement inside of an if clause, only to remember that those can only be used for loops.

Lets take the following code as an example:

if some_condition:
   ...
   if condition_a:
       # do something
       # and then exit the outer if block
   ...
   if condition_b:
       # do something
       # and then exit the outer if block
   # more code here

I can think of one way to do this: assuming the exit cases happen within nested if statements, wrap the remaining code in a big else block. Example:

if some_condition:
   ...
   if condition_a:
       # do something
       # and then exit the outer if block
   else:
       ...
       if condition_b:
           # do something
           # and then exit the outer if block
       else:
           # more code here

The problem with this is that more exit locations mean more nesting/indented code.

Alternatively, I could write my code to have the if clauses be as small as possible and not require any exits.

Does anyone know of a good/better way to exit an if clause?

If there are any associated else-if and else clauses, I figure that exiting would skip over them.

Anabolite answered 15/1, 2010 at 5:20 Comment(4)
For your second code sample--do you know about elif?Travis
"Alternatively, I could write my code to have the if clauses be as small as possible and not require any exits." -- and surely this would be the best course of action. :-)Chigetai
@Craig McQueen: I do, but say I wanted to have code execute between condition statements? E.g. if a: #stuff; #stuff_inbetween; if b: #stuff; The inbetween code depends on not a but doesn't depend on b.Anabolite
hello please don't forget elif https://mcmap.net/q/150501/-how-to-exit-an-if-clauseThoer
I
151

This method works for ifs, multiple nested loops, and other constructs that you can't break from easily.

  1. Wrap the code in its own function.
  2. Instead of break, use return.

Example:

def some_function():
    if condition_a:
        # do something and return early
        ...
        return
    ...
    if condition_b:
        # do something else and return early
        ...
        return
    ...
    return

if outer_condition:
    ...
    some_function()
    ...
Interleaf answered 15/1, 2010 at 5:24 Comment(6)
Oh, I like that idea. It seems like it might have the downside of being slower, though. The PythonWiki performance tips page says "Function call overhead in Python is relatively high" (wiki.python.org/moin/PythonSpeed/PerformanceTips)Anabolite
I'm happy to add to your bag of programmer tricks. In my experience, that approach works nearly every time you're tempted to use a forward-moving goto. (And it both hints at and addresses situations where a single function is getting too big)Interleaf
Ideally you can achieve both, but there are times when you must trade good code for good performance. Those times are rare, especially when you are considering using Python. In other words: don't worry so much about function call overhead.Stome
There's an old anecdote: "Dennis Ritchie encouraged modularity by telling all and sundry that function calls were really, really cheap in C. Everybody started writing small functions and modularizing. Years later we found out that function calls were still expensive on the PDP-11, and VAX code was often spending 50% of its time in the CALLS instruction. Dennis had lied to us! But it was too late; we were all hooked..."Stome
@ephemient: That's funny, is there more to the story? I'd like to read the whole thing.Anabolite
This quotation is from chapter 4 of the book The Art of Unix Programming (online at faqs.org/docs/artu). You really should read the whole thing, if you haven't before.Stome
S
86
from goto import goto, label

if some_condition:
   ...
   if condition_a:
       # do something
       # and then exit the outer if block
       goto .end
   ...
   if condition_b:
       # do something
       # and then exit the outer if block
       goto .end
   # more code here

label .end

(Don't actually use this, please.)

Stome answered 15/1, 2010 at 5:29 Comment(10)
+1 because this is funny. A google search revealed to me that this was an April Fool's joke module.Anabolite
I linked to it, too. Click on the first goto.Stome
this reminds me of assembly code with all kinds of branching :)Merozoite
@ephemient: Ah, didn't notice the link. Figured it was code highlighting. But now that I look at your code, I don't see any real highlighting going on..Anabolite
When PHP introduced goto I turned to Python php.net/manual/en/control-structures.goto.phpLoats
I would prefer goto over elif :)Medicament
@Stome just out of curiosity, why shouldn't we ever use this?Latterday
@BenGubler because it was intended as an april fools joke. I mean, you could use it, but probably shouldn't for production use cases.Barneybarnhart
Goto is a Python 2 library... I was going to use it for an actual program for my company... disappointing bc I'm using python 3 nowSwam
@Medicament - sometimes, indeed! Anti-goto-ers make this a religion and it's sad...Subjectivism
F
36
while some_condition:
   ...
   if condition_a:
       # do something
       break
   ...
   if condition_b:
       # do something
       break
   # more code here
   break
Flaunty answered 19/1, 2010 at 2:5 Comment(2)
Oh, hey I really like this idea. I think this exactly solves my original desire. However, I have a nagging feeling that this is not good practice (and for that reason, I'll retain the current accepted answer for now because it promotes good coding style).Anabolite
Note that you could keep the original if and wrap the entire thing in a while True:. Just make sure to put in a break statement at the end! For languages with the do-while construct, it is more idomatic to do: do { code that can conditionally break out } while (false);Flaunty
I
13

You can emulate goto's functionality with exceptions:

try:
    # blah, blah ...
    # raise MyFunkyException as soon as you want out
except MyFunkyException:
    pass

Disclaimer: I only mean to bring to your attention the possibility of doing things this way, while in no way do I endorse it as reasonable under normal circumstances. As I mentioned in a comment on the question, structuring code so as to avoid Byzantine conditionals in the first place is preferable by far. :-)

Insnare answered 15/1, 2010 at 5:35 Comment(2)
Haha, I like this creative solution. Though I will abide your disclaimer and not use such funky code.Anabolite
@Roman: Happy to add another trick alongside Shmoopty's -- even when I feel naughty in comparison. ;-)Chigetai
P
12

may be this?

if some_condition and condition_a:
       # do something
elif some_condition and condition_b:
           # do something
           # and then exit the outer if block
elif some_condition and not condition_b:
           # more code here
else:
     #blah
if
Principle answered 15/1, 2010 at 5:28 Comment(2)
Yeah, that could work. I think my mind sort of blanked on elif while I was writing this. Although I think this would not work in a situation where I want code to execute in between the nested if statements.Anabolite
this is actually the correct answer. why I don't see people recommend this?? :)Thoer
T
12

For what was actually asked, my approach is to put those ifs inside a one-looped loop

for _ in range(1):
    if (some_condition):
        # do something applicable to all condition
        ...
        if (condition_a):
            # do something
            # and then exit the outer if block
            break
        # do something applicable to some_condition but not for condition_a 
        ...
        if (condition_b):
            # do something
            # and then exit the outer if block
            break
        # do something applicable to some_condition but neither for condition_a/b
        ...

Using this instead of using combination of elif & and, will help you write DRY(don't repeat yourself) code. If you are using elif & and, you might need to rewrite # do something applicable to all condition or other line multiple times. Which is less clean even if the line is just a function call.

Test it:

conditions = [True,False]
some_condition = True

for condition_a in conditions:
    for condition_b in conditions:
        print("\n")
        print("with condition_a", condition_a)
        print("with condition_b", condition_b)
        while (True):
            if (some_condition):
                print("checkpoint 1")
                if (condition_a):
                    # do something
                    # and then exit the outer if block
                    print("checkpoint 2")
                    break
                print ("checkpoint 3")
                if (condition_b):
                    # do something
                    # and then exit the outer if block
                    print("checkpoint 4")
                    break
                print ("checkpoint 5")
                # more code here
            # make sure it is looped once
            break
Travesty answered 8/9, 2015 at 8:10 Comment(3)
To be honest, this is the cleanest solution. It's very clear when the code is to exit - you don't have to worry about function scoping inside functions, and there is zero performance or logical debt.Eckert
Might consider using for _ in range(1): instead of while True:. (1) Better communicate your intention of a single iteration loop and (2) no last break statement to exit the loop (might be removed by accident later on)Calibre
@BernhardKausler I found that independently and seriously considered it because my top-level was "if verbose," so for _ in range(verbose): worked... but then I was able to refactor it away.Tonsil
S
5

Generally speaking, don't. If you are nesting "ifs" and breaking from them, you are doing it wrong.

However, if you must:

if condition_a:
   def condition_a_fun():
       do_stuff()
       if we_wanna_escape:
           return
   condition_a_fun()
if condition_b:
   def condition_b_fun():
       do_more_stuff()
       if we_wanna_get_out_again:
           return
   condition_b_fun()

Note, the functions don't HAVE to be declared in the if statement, they can be declared in advance ;) This would be a better choice, since it will avoid needing to refactor out an ugly if/then later on.

Sclater answered 15/1, 2010 at 6:55 Comment(2)
Thanks for the answer. I'm not sure what you mean by 'nesting loops'. If you are referring to my mention of the keyword 'break', I was simply trying to motivate my search for an if-exit by comparing it to the existence of a loop exit. Also, I am unsure how your code solves the problem, as my example had if condition_a and if condition_b nested inside an if some_condition. I want to be able to break out of the if some_condition.Anabolite
The reason people want to nest ifs and breaking them is probably not because they are doing it wrong, but maybe because they want to write clean simple and DRY code. simple case is when the program needs to do x() when both condition_a and condition_b fulfilled, and needs to do y() only for condition_a, and needs to do z() only for condition_b. and the coder refuse to write x() multiple timeTravesty
T
5

There is another way which doesn't rely on defining functions (because sometimes that's less readable for small code snippets), doesn't use an extra outer while loop (which might need special appreciation in the comments to even be understandable on first sight), doesn't use goto (...) and most importantly let's you keep your indentation level for the outer if so you don't have to start nesting stuff.

if some_condition:
   ...
   if condition_a:
       # do something
       exit_if=True # and then exit the outer if block
if some condition and not exit_if: # if and only if exit_if wasn't set we want to execute the following code
   # keep doing something
   if condition_b:
       # do something
       exit_if=True # and then exit the outer if block
if some condition and not exit_if:
   # keep doing something

Yes, that also needs a second look for readability, however, if the snippets of code are small this doesn't require to track any while loops that will never repeat and after understanding what the intermediate ifs are for, it's easily readable, all in one place and with the same indentation.

And it should be pretty efficient.

Touslesmois answered 7/11, 2018 at 8:24 Comment(0)
U
4

Here's another way to handle this. It uses a single item for loop that enables you to just use continue. It prevents the unnecessary need to have extra functions for no reason. And additionally eliminates potential infinite while loops.

if something:
    for _ in [0]:
        # Get x
        if not x:
            continue

        # Get y
        if not y:
            continue

        # Get z
        if not z:
            continue

        # Stuff that depends on x, y, and z
Unselfish answered 15/4, 2020 at 18:18 Comment(5)
This might work out well for some situation! However, if the programmer is taking into account Big O notation, this might not be a good solution as it can be expensive to be using for loop. Any thoughts?Likeminded
@Likeminded that analysis doesn't actually make any sense. Big-O notation isn't simply about the number of nested loops, and simply writing a for loop doesn't incur overhead in itself - what matters is the number of times the nested code runs. for _ in [0]: loops once, because [0] has one item in it. Multiplying the amount of work by 1 doesn't make it bigger.Royden
As ugly as it is to create blocks artificially like this, I think for _ in [0]: is definitely more elegant than using a while loop and remembering to break it unconditionally at the end. On the other hand, the while approach allows continue to restart the process in addition to break aborting it.Royden
@KarlKnechtel i agree with you definitely. What if the [0] gets larger? Would your statement still stands? Pardon my naive thinking of this situation! still learning everydayLikeminded
I don't understand what you mean by "gets larger". If you're asking how to make code loop a set number of times, then the usual Python idiom is to make a range and iterate over it. But if you've decided that the code now needs to loop, then you're probably going to have to rethink the entire thing anyway.Royden
P
3

Effectively what you're describing are goto statements, which are generally panned pretty heavily. Your second example is far easier to understand.

However, cleaner still would be:

if some_condition:
   ...
   if condition_a:
       your_function1()
   else:
       your_function2()

...

def your_function2():
   if condition_b:
       # do something
       # and then exit the outer if block
   else:
       # more code here
Picklock answered 15/1, 2010 at 5:29 Comment(0)
J
1

So here i understand you're trying to break out of the outer if code block

if some_condition:
    ...
    if condition_a:
       # do something
       # and then exit the outer if block
       ...
    if condition_b:
       # do something
       # and then exit the outer if block
# more code here

One way out of this is that you can test for for a false condition in the outer if block, which will then implicitly exit out of the code block, you then use an else block to nest the other ifs to do something

if test_for_false:
    # Exit the code(which is the outer if code)

else:
    if condition_a:
        # Do something

    if condition_b:
        # Do something
Jaffe answered 31/5, 2018 at 12:23 Comment(0)
T
1

The only thing that would apply this without additional methods is elif as the following example

a = ['yearly', 'monthly', 'quartly', 'semiannual', 'monthly', 'quartly', 'semiannual', 'yearly']
# start the condition
if 'monthly' in b: 
    print('monthly') 
elif 'quartly' in b: 
    print('quartly') 
elif 'semiannual' in b: 
    print('semiannual') 
elif 'yearly' in b: 
    print('yearly') 
else: 
    print('final') 
Thoer answered 28/7, 2020 at 19:31 Comment(0)
P
1

There are several ways to do it. It depends on how the code is implemented.

If you exit from a function, then use return; no code will be executed after the return keyword line. Then the example code is:

def func1(a):
    if a > 100:
        # some code, what you want to do
        return a*a 
    if a < 100:
         # some code, what you want to do
        return a-50
    if a == 100:
         # some code, what you want to do
        return a+a

If you exit from a loop, use break. No code will be executed after break keyword. Then the example code is, for while and for loops:

a = 1
while (True):
    if (a == 10):
        # some code, what you want to do
        break
    else:
        a=a+1
        print("I am number", a)

for i in range(5):
    if i == 3:
        break
    print(i)

If you exit from the basic conditional, then you can use the exit() command directly. Then code after the exit() command will not be executed.

NB: This type of code is not preferable. You can use a function instead of this. But I just share the code for example.

The example code is:

if '3K' in FILE_NAME:
        print("This is MODIS 3KM file")
        SDS_NAME = "Optical_Depth_Land_And_Ocean"
        
    elif 'L2' in FILE_NAME:
        print("This is MODIS 10KM file")
        SDS_NAME = "AOD_550_Dark_Target_Deep_Blue_Combined" 
        exit()
    else:
        print("It is not valid MODIS file")
Preciousprecipice answered 15/1, 2023 at 5:57 Comment(0)
B
0

I scrolled through, and nobody mentioned this technique. It's straightforward compared to other solutions and if you do not want to use a try-except statement, this may be your best option.

#!/usr/bin/python3
import sys

foo = 56

if (foo != 67):
    print("ERROR: Invalid value for foo")
    sys.exit(1)
Babbage answered 16/8, 2022 at 6:47 Comment(1)
this does not work as desired b/c this exits the entire python program ... the original question does not want to exit the program but instead continue on to the next conditional statement(s)Peasant
B
-2

use return in the if condition will returns you out from the function, so that you can use return to break the the if condition.

Beersheba answered 18/10, 2018 at 10:13 Comment(2)
he wants to break the if not exit the functionMessner
This would work if another function were created to wrap the inner code. However, the top/accepted answer already describes exactly that.Royden

© 2022 - 2024 — McMap. All rights reserved.