If vs. Elif in Python, which is better?

Question:

I am reading Grokking Algorithms, which seems to be a highly recommended book. I am looking at the first algorithm for “binary search” and the guy uses two “ifs” instead of a “if” and “elif”. Would using two “ifs” be better or faster?

def binary_search(list, item):
    low = 0
    high = len(list) - 1

    while low <= high:
        mid = (low + high)
        guess = list[mid]
        if guess == item:
            return mid
        if guess > item:
            high = mid - 1
        else:
            low = mid + 1
    return None

my_list = [1,3,5,7,9]

Answers:

example1

>>> def foo():
    a = 10
    if a == 10:
        print("condition1")
    elif a == 10:
        print("condition2")
    else:
        print(0)    
>>> foo()
condition1
>>> 

elif is guaranteed not to run when if is true.

example2

def foo():
    a = 10
    if a == 10:
        print("condition1")
    if a == 10:
        print("condition2")
    else:
        print(0)
>>> foo()
condition1
condition2
>>> 

example3
modify if statement of example2.

if a == 10:
    print("condition1")
    return a

output

>>> foo()
condition1
10

So, in your case adding a return in first if statement has similar operation like an if-elif block. the (return a) is preventing the second if statement to be executed in example3.

Answered By: sage07

Multiple IFs

You use multiple ifs, when you want to accomplish different tasks that are independent of each other. And the execution of one of the tasks doesn’t effect the execution of others.

Let’s look at an example:

if primeMember:
  makeDeliveryFree()
if validDiscountCoupon:
  giveDiscount(couponCode)
if customersBirthday:
  giveBirthdayDiscount()

So, in the above example we have different tasks that we want to perform under different conditions and the tasks are independent of each other. Making the delivery free doesn’t effect the discount in any manner.

With multiple ifs, it could be possible that the statements within all the ifs get executed and on the other hand it could also be possible that none of the statements within the ifs get executed.

IF, ELIF, ELSE Chain

On the other hand we would use an if, elif, else chain, when we want to accomplish a particular task but we want accomplish that differently under different conditions.

Let’s look at an example:

if hasBalanceInWallet:
  setPaymentMode("wallet")
elif hasCreditCardSaved:
  setPaymentMode("credit-card")
else
  showPaymentModeSelectorDialog()

So, in the above example the task that we’re trying to accomplish is that of setting the mode of payment and we need to set it differently under different scenarios but we only want to set it once (i.e. we want only one of the branches to run).

As other answers mentioned, an elif is not necessary after an if that does a return. But they didn’t cover the performance impact. I thought it would be interesting to test.

Turns out, it can be a tad faster to use if/elif/else instead of separate if‘s.

from timeit import timeit
import random


def count_items_ifelifelse(items, threshold):
    below, on, above = 0, 0, 0
    for item in items:
        if item > threshold:
            above += 1
        elif item < threshold:
            below += 1
        else:
            on += 1
    return below, on, above


def count_items_ififif(items, threshold):
    below, on, above = 0, 0, 0
    for item in items:
        if item > threshold:
            above += 1
        if item < threshold:
            below += 1
        if item == threshold:
            on += 1
    return below, on, above


def generate_items_and_threshold(count=100_000):
    """List of reproducible random numbers to test with. Set threshold at half"""
    items = list(range(count))
    random.Random(123).shuffle(items)
    threshold = count // 2
    return items, threshold


def run_test():
    t1 = timeit(
        "count_items_ifelifelse(i, t)",
        setup="from __main__ import count_items_ifelifelse, generate_items_and_threshold; i, t = generate_items_and_threshold()",
        number=1000,
    )
    print("count_items_ifelifelse: {:.2f}".format(t1))
    t2 = timeit(
        "count_items_ififif(i, t)",
        setup="from __main__ import count_items_ififif, generate_items_and_threshold; i, t = generate_items_and_threshold()",
        number=1000,
    )
    print("count_items_ififif: {:.2f}".format(t2))


if __name__ == "__main__":
    run_test()

This outputs (Python 3.8.2, Windows):

count_items_ifelifelse: 6.69
count_items_ififif: 8.71

Roughly 20% faster, because of more unnecessary if evaluations each loop. The other side of it is that for if/elif/else the performance will vary based on how the data is sorted, and whether it checks the most occurring condition first.

Answered By: MarkM
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.