views:

360

answers:

9

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.

+10  A: 

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

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

Shmoopty
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" (http://wiki.python.org/moin/PythonSpeed/PerformanceTips)
Roman Stolper
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)
Shmoopty
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.
ephemient
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..."
ephemient
@ephemient: That's funny, is there more to the story? I'd like to read the whole thing.
Roman Stolper
This quotation is from chapter 4 of the book The Art of Unix Programming (online at http://www.faqs.org/docs/artu/). You really should read the whole thing, if you haven't before.
ephemient
+2  A: 

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
ghostdog74
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.
Roman Stolper
+1  A: 

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
Smashery
+4  A: 
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.)

ephemient
+1 because this is funny. A google search revealed to me that this was an April Fool's joke module.
Roman Stolper
I linked to it, too. Click on the first `goto`.
ephemient
this reminds me of assembly code with all kinds of branching :)
phunehehe
@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..
Roman Stolper
+4  A: 

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

Michał Marczyk
Haha, I like this creative solution. Though I will abide your disclaimer and not use such funky code.
Roman Stolper
@Roman: Happy to add another trick alongside Shmoopty's -- even when I feel naughty in comparison. ;-)
Michał Marczyk
A: 

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.

Enki
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`.
Roman Stolper
A: 

I don't like the whole idea of structuring code this way. I fear it leads to the same problems as using goto statements. (luckily, Python has not goto statement).

Ber
I'm a little confused, which way? Trying to exit `if` s early or are you responding to one of the answers?
Roman Stolper
+1  A: 
while some_condition:
   ...
   if condition_a:
       # do something
       break
   ...
   if condition_b:
       # do something
       break
   # more code here
   break
trinithis
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).
Roman Stolper
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);`
trinithis
A: 

I like trinithis' idea (Using while instead of if). But what if I wanna break an else clause not an if clause. It would be redundant to check the condition since it's already in else, no??

vally
I think trinithis's comment on his own answer might address that.
Roman Stolper