Reputation: 1690
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
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
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