-2

The following code works for me but is there a more condensed way to do repeated nested if statements?

for i in range(5):
    if True:
        do_something()
        if True:
           do_something()
           if True:
                do_something()
                if True: 
                    do_something()
                    if True:
                        do_something()
Daman
  • 27
  • 4
  • Yes. Refactor. Split up the inner statements into a function whose name accurately represents what they do. Each individual function of your code should be short and single-purpose. – Silvio Mayolo Mar 19 '22 at 00:40
  • I understand I can refactor but if the statement before must also be true then wouldn't I still end up with a long tree? – Daman Mar 19 '22 at 01:02

1 Answers1

1

There are several different tactics, depending on the situation. In this case, all of your ifs are trivial, but let's pretend they are all different, non-trivial conditions:

for i in range(5):
    if condition1:
        do_something()
        if condition2:
           do_something()
           if condition2=3:
                do_something()
                if condition4: 
                    do_something()
                    if condition5:
                        do_something()

You can replace that with

for i in range(5):
    for condition in [condition1, condition2, condition3, condition4, condition5]:
        if condition:
            do_something()
        else:
            break

If you have different do_something()s, then you can do

condition_action_lookup = {condition1: action1,
                               ...
                          }
for i in range(5):
    for condition, action in condition_action_lookup.items():
        if condition:
            action
        else:
            break

There's also Silvio Mayolo's advice in the comments to use functions. One way to do this is:

 def level1():
     if condition1:
         action1
         level2()
 def level2():
     if condition2:
         action2
         level3()
 def level3():
     if condition3:
         action3
         level4()
 def level4():
     if condition4:
         action4
         level5()
 def level5():
     if condition5:
         action5

 for i in range(5):
      level1()

Also, a trap people can fall into is splitting conjunctions into separate if cases. That is, instead of doing

if a and b:
    do_something()

They'll do

if a:
    if b:
        do_something()

While there are some cases where the second is better (if a is False, you save time by not checking b, and evaluating b might return an error if a is False), the first is generally simpler. Furthermore, Python actually automatically skips the b in a and b if a is False (this is known as short-circuiting). If you want the do_something() only once, if all of the conditions are met, you can do just

if all([condition1, condition2, condition3, condition4, condition5]):
    do_something()

If you want to know how many conditions it went through, you can do num_cond_satified = sum(conditions). If you want to short-circuit, there are a few ways:

num_cond_satified = 0
for condition in conditions:
    if not condition:
        break
    num_cond_satified +=1
if num_cond_satified == len(conditions):
    do_something()

Or use this question and do

num_cond_satified = next((i for i, condition in enumerate(conditions) if not condition), len(conditions))`
if num_cond_satified == len(conditions):
    do_something()
Acccumulation
  • 3,491
  • 1
  • 8
  • 12
  • This is extremely helpful! The first method works. I'm realizing that I don't actually need to do_something until the last condition is met rather than each time a condition is met. Is there a way to do_something once only once and know how many conditions it went through? – Daman Mar 19 '22 at 17:35
  • @DamanCoffman I've edited to include that case. – Acccumulation Mar 19 '22 at 20:56