3

Whenever I'm coding something that requires a lot of conditionals, I end up doing this:

if foo:
 if bar:
 if foobar:
 if barfoo:
 if foobarfoo:
 if barfoobar:
 # And forever and ever and ever

I can't write if foo and bar and foobar and ... because I check for the value list elements (if foo[1] == 'bar') inside of an if somewhere down the line, and if the list index don't exist, I get an error.

Is there a shortcut to conditionally checking things like this, or an alternative method? Thanks.

asked Feb 12, 2011 at 0:33
3
  • 2
    What do you mean by "I call list elements inside of an if?"
    wheaties
    Commented Feb 12, 2011 at 0:37
  • Question is sort of vague as to what "sequential conditionals" is or why the "one expression" form wouldn't work -- and/or are short-circuited.
    user166390
    Commented Feb 12, 2011 at 0:41
  • Sorry for the ambiguities. I've updated the question.
    Blender
    Commented Feb 12, 2011 at 1:01

7 Answers 7

9

I can't write if foo and bar and foobar and ... because I call list elements inside of an if somewhere down the line, and if the list index don't exist, I get an error.

in python,and short circuits. If the left side of the expression is false, the right side is not evaluated at all.

foo = dict()
if 'bar' in foo and foo['bar']:
 doSomething()
answered Feb 12, 2011 at 0:37
3
  • I didn't know that Python short-circuited. That makes life a lot easier.
    Blender
    Commented Feb 12, 2011 at 2:03
  • @Blender: then probably you'll have to mark TokenMacGuy's answer as the answer, since the currently selected Lacrymology's one does not help at all with short circuiting.
    tzot
    Commented Oct 15, 2011 at 9:28
  • @tzot: my answer was previously accepted. I suppose op finds Lycramology's answer more stimulating. Commented Oct 15, 2011 at 14:25
5

Fail fast:

if not foo:
 return
if not foobar:
 return

and so forth.

answered Feb 12, 2011 at 0:34
3

There's also

if all((foo, bar, foobar, barfoo, foobarfoo, barfoobar)):
 print "oh yeah"

all will also shortcircuit

answered Sep 28, 2011 at 3:45
2
  • Now this is more like it. A bit late to answer, but this is much easier. Thanks!
    Blender
    Commented Sep 28, 2011 at 15:21
  • no problem, you can also do if all([obj.property for obj in obj_list]) for example Commented Oct 4, 2011 at 16:53
2

Forgive me if I'm stating the obvious -- but if you're checking for many different conditions in advance of one or two operations, you might be better off using try/except -- especially for those conditions (if any) that are clear error conditions.

answered Feb 12, 2011 at 1:54
1
  • 1
    Especially if those conditions may change (perhaps by external factors) by the time you have finished all of your checks. More so if the usual case is for all to succeed: try:except: is fast, unless you actually hit an exception. Commented Feb 12, 2011 at 8:37
1

See if you can't break some of that out into a function that includes some of the conditionals (assuming some are in common with your various cases).

answered Feb 12, 2011 at 0:42
1
  • @wheaties: This response attempts to solve the problem posed in the original question. There's no reason for it to be a comment. comments are not solutions to the original problem. Commented Feb 12, 2011 at 4:19
0

Break it up into several sub-components where appropriate. As for where to draw the dividing lines, that's really up to you. While a huge staircase of conditional statements isn't great, neither is a massive if-statement with so many predicates that they wrap several lines. Instead, try to group your conditions into logical bunches.

You might write it as:

if foo and bar and foobar:
 ...
 if barfoo and foobarfoo and barfoobar:
 ...

I also suggest introducing helper methods along the way. Even if those helper methods are called only from this code, that's fine.

def handle_bar():
 if barfoo and foobarfoo and barfoobar:
 ...
if foo and bar and foobar:
 ...
 handle_bar()

If scopes get confusing or you find yourself passing around too much state as function arguments, wrap it in a class and use member variables where its conceptually appropriate.

Overall, my advice is to separate concepts into individual pieces of code at an appropriate granularity. If you don't do it at all, you get a long piece of code that requires lots of scrolling to see the big picture. If you over-do it, you force the reader to jump around your code too much.

answered Feb 12, 2011 at 0:45
0

If you have more than 3 to 5 tests (or more), consider keeping your conditions in a dictionary, list or tuple. Then test that data structure. Much cleaner than many individual named data.

If you are testing "truth" against a named list of variables of unknown length or a sequence data structure (like a list or tuple) you can do this:

def all_true(*args):
 for test in args:
 if bool(test) is False: return False 
 return True 
foo=bar=foobar=barfoo=foobarfoo=barfoobar=1
if foo:
 if bar:
 if foobar:
 if barfoo:
 if foobarfoo:
 if barfoobar:
 print "True by Stairs!"
if all_true(foo,bar,foobar,barfoo,foobarfoo,barfoobar):
 print "True by function!"
t=(foo,bar,foobar,barfoo,foobarfoo,barfoobar)
if all_true(*t): print "The tuple is true!"
l=[foo,bar,foobar,barfoo,foobarfoo,barfoobar]
if all_true(*l): print "list is true!"
bar=0
# run the same tests...

The all_true() function will short-circuit against the first false it finds.

answered Feb 12, 2011 at 8:15

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.