Siraj Samsudeen
Siraj Samsudeen

Reputation: 1690

What is the pythonic way of writing a long if-else statement?

I am quite new to Python though I have had experience in Java before.

I have the following code to convert a score into an interval delta (as part of a Spaced Repetition System (SRS) program I am implementing). This code looks ugly and not very readable. Typically I would have used a switch statement in Java. But in python I could not find an equivalent. Hence I have written this code which produces the result. But I want to take this opportunity to learn different options for achieving the same output using more pythonic ways. I would appreciate any help, even if they are pointers to resources that I can read to improve this code.

   # Convert score into an interval delta
    if score == 0:  # Perfect page
        intervalDelta = +3
    elif score == 1:  # 1 Word Mistake
        intervalDelta = +2
    elif score <= 3:  # 3 Word Mistakes
        intervalDelta = +1
    elif score == 4:  # 1 Line Mistake
        intervalDelta = 0
    elif score <= 8:  # 2 Line Mistakes
        intervalDelta = -1
    elif score <= 12:  # 3 Line Mistakes
        intervalDelta = -2
    elif score <= 20:  # 5 Line Mistakes
        intervalDelta = -3
    elif score <= 30:  # 7.5 Line Mistakes - Half a page
        intervalDelta = -5
    else:  # More than half a page
        intervalDelta = -7

Upvotes: 5

Views: 1187

Answers (2)

datasmith
datasmith

Reputation: 764

The official position on switch statements is that switch statements are easily done with if statements, so writing long if statements is the Python way. PEP 275 and PEP3103 document the reasons why switch statements were omitted. In practice though there are several alternatives to the switch statement.. The most common is the dictionary approach to switches.

def case_a():
  print('Executing case A')

def case_b():
  print('Executing case B')

def case_else()
  print('Executing default case')

def dict_switch(argument):
    switch = {
        'a': case_a
        'b': case_b
    }
    return switch.get(argument, case_else)()

dict_switch(x)

Another approach is to keep all of the conditional logic in a class, but I find this is only necessary when there is a significant amount of conditional logic.

class Switcher:
    def numbers_to_methods_to_strings(self, argument):
        """Dispatch method"""
        # prefix the method_name with 'number_' because method names
        # cannot begin with an integer.
        method_name = 'number_' + str(argument)
        # Get the method from 'self'. Default to a lambda.
        method = getattr(self, method_name, lambda: "nothing")
        # Call the method as we return it
        return method()

    def number_0(self):
        return "zero"

    def number_1(self):
        return "one"

    def number_2(self):
        return "two"

In your case, however, I think @asthasr approach is the cleanest.

Upvotes: 1

asthasr
asthasr

Reputation: 9417

I don't find the long if statement that unreadable, although I'd change to using <= for consistency (since the == cases are already single possibilities using <=). If I were implementing it from scratch, I'd probably write something like the following simply to have the associations more visible:

from math import inf


SCORE_DELTAS = (
    (0, +3),
    (1, +2),
    (3, +1),
    (4, +0),
    (8, -1),
    (12, -2),
    (20, -3),
    (30, -5),
    (inf, -7),
)


def score_to_delta(score):
    for bound, delta in SCORE_DELTAS:
        if score <= bound:
            return delta

Upvotes: 7

Related Questions