if or elif either true then do something

this is just for academic interest. I encounter the following situation a lot.

either_true = False
if x:
  ...do something1
  either_true = True
elif y:
  ...do something2
  either_true = True
if either_true:
  ..do something3

is there any pythonic way of doing it, or in general better programming way of doing it. Basically do something3 executes only if or elif is true.


Solution 1:

You could also omit the either_true flag completely if doSomething3 is a single line of code (e.g. a function call):

if x:
  ..do something 1
  ..do something 3
elif y:
  ..do something 2
  ..do something 3

It maintains the nice property of evaluating x and y at most once (and y won't be evaluated if x is true).

Solution 2:

Your code is almost optimal, as far as code repetition and evaluation are concerned. The only thing I can think of to avoid repetition would be:

# be optimistic!
either_true = True
if x:
    do_something1
elif y:
    do_something2
else:
    either_true = False

if either_true:
    do_something3

This removes one assignment, although the total number of lines doesn't change.

The advantage is that this works with n conditions, without adding any other assignment, while your current solution requires an either_true = True for every condition.

In my opinion they have about the same degree of readability, but the above code will be better with more conditions.

Also there's no "pythonic" way other then a readable solution that avoids code repetition and is optimal in terms of efficiency, and I don't know of any kind of "better programming" to achieve the same result.

Solution 3:

I would handle this by using nested if statements i.e.

if x or y:
    if x:
        ...do something1
    elif y:
        ...do something2
    ...do something3

As some comments have pointed out, the best solution will depend on what x & y are. If easy readability / concise code is your goal then this or other answers given should be fine. If however x & y were expensive function calls then it would be better to do something more like what you have done to avoid calling the function twice.

Solution 4:

You could wrap some of it in a function:

def do_stuff():
    if x:
        ...do something1
        return True
    elif y:
        ...do something2
        return True
    else:
        return False

if do_stuff():
    ..do something3

Or all of it in a function:

def do_stuff()
    if x:
        ...do something1
    elif y:
        ...do something2
    else:
        return

    ..do something3

Solution 5:

if x or y:
    dosomethig1() if x else dosomething2()
    dosomething3()

Of course, this does evaluate x.__nonzero__ twice. Usually that's not a big deal, but if it is expensive, you can always evaluate that upfront and save it to a temporary variable.