UPD END
Для начала, ничего особенно плохого в использовании конструкции if-elif-else нет.
При желании можно найти несколько альтернатив.
Использование словарей
Довольно распространённый способ организации конструкции switch-case в Python — это использование словаря. Проще показать на примере:
unit_to_multiplier = { 'mm': 10**-3, 'cm': 10**-2, 'dm': 10**-1, 'm': 1, 'km': 10**3}
Для того, чтобы получить нужный множитель в этом случае требуется лишь взять значение по ключу:
try: mult = unit_to_multiplier['cm']except KeyError as e: raise ValueError('Undefined unit: {}'.format(e.args[0]))
Если вы твёрдо уверены, что значение всегда будет присутствовать в словаре, можете опустить блок try-except и быть готовым ловить исключение в другом месте.
Некоторой вариацией этого подходя будет предварительная проверка значения в условии:
if unit in unit_to_multiplier: mult = unit_to_multiplier[unit]else:
В Python принято использовать подход, звучащий примерно так: "лучше попробовать и получить ошибку, чем каждый раз спрашивать разрешение", поэтому более предпочтительный подход с использованием исключений.
Если хочется использовать значение по умолчанию в случае, если ключ отсутствует, удобно использовать метод get:
mult = unit_to_multiplier.get('ultra-meter', 0)
Если словарь вам требуется один раз, можно объединить эти выражения в одно:
unit_to_multiplier = { 'mm': 10**-3, 'cm': 10**-2, 'dm': 10**-1, 'm': 1, 'km': 10**3}.get('km', 0)
На этом возможности этого подхода не заканчиваются. Можно использовать условные выражения в качестве ключей словаря:
def get_temp_description(temp): retu { temp < -20: 'Холодно', -20 <= temp < 0: 'Прохладно', 0 <= temp < 15: 'Зябко', 15 <= temp < 25: 'Тепло', 25 <= temp: 'Жарко' }[True]
Этот словарь после вычисления будет иметь два ключа True и False. Нас интересует ключ True. Будьте внимательны, что условия не перекрываются!
Подобные словари могут проверять произвольное свойство, например, тип ():
selector = { type(x) == str : "it's a str", type(x) == tuple: "it's a tuple", type(x) == dict : "it's a dict"}[1]
При необходимости более сложных действий хранить функцию в качестве значения по каждому ключу:
import operatoroperations = { '+': operator.add, '*': lambda x, y: x * y, }def calc(operation, a, b): retu operations[operation](a, b)
Будьте внимательны при использовании словаря с функциями — убедитесь, что вы не вызываете эти функции внутри словаря, а передаёте по ключу; иначе все функции будут выполняться каждый раз при конструировании словаря.
Другие способы
Приведены скорее для ознакомления, чем для реального использования.
Создадим класс, в котором напишем несколько методов вида:
def process_first(self): ... def process_second(self): ... ...
И один метод-диспетчер:
def dispatch(self, value): method_name = 'process_' + str(value) method = getattr(self, method_name) retu method()
После этого можно использовать метод dispatch для выполнения соответствующей функции, передавая её суффикс, например x.dispatch('first').
Использование специальных классов
Если есть желание использовать синтаксис switch-case в максимально похожем стиле, можно написать что-то вроде следующего :
class switch(object): def __init__(self, value): self.value = value self.fall = False def __iter__(self): """ Возвращает один раз метод match и завершается """ yield self.match raise StopIteration def match(self, *args): """ Указывает, нужно ли заходить в тестовый вариант """ if self.fall or not args: retu True elif self.value in args: self.fall = True retu True retu False
Используется следующим образом:
x = int(input()) for case in switch(x): if case(1): pass if case(2): pass if case(3): print('Число от 1 до 3') break if case(4): print('Число 4') if case(): print('Другое число')
.
Довольно небезопасный способ, см. пример:
Select Case x Case x<0 : y = -1 Case 0<=x<1 : y = 0 Case 1<=x<2 : y = 1 Case 2<=x<3 : y = 2 Case Else : y = 'n/a' End Select y = (( x < 0 and 'first segment') or (0 <= x < 1 and 'second segment') or (1 <= x < 2 and 'third segment') or (2 <= x < 3 and 'fourth segment') or 'other segment')
Этот способ использует короткую схему вычисления операторов and и or, т.е. то, что логические выражения вычисляются следующим образом:
(t вычисляющееся как True, f вычисляется как False):
f and x = f t and x = x f or x = x t or x = t
П��едложенный способ вычислений будет работать только в том случае, если второй аргумент оператора and всегда будет содержать True-выражение, иначе этот блок всегда будет пропускаться. Например:
y = (( x < 0 and -1) or (0 <= x < 1 and 0) or (1 <= x < 2 and 1) or (2 <= x < 3 and 2) or 'n/a')
Будет работать неправильно в случае 0 <= x < 1, т.к. выражение 0 <= x < 1 and 0 равно 0, и из-за этого управление перейдёт следующему аргументу or, вместо того, чтобы вернуть этот ноль в качестве результата выражения.
Если объявить несколько функций:
import sys class case_selector(Exception): def __init__(self, value): Exception.__init__(self, value) def switch(variable): raise case_selector(variable) def case(value): exc_сlass, exс_obj, _ = sys.exc_info() if exc_сlass is case_selector and exс_obj.args[0] == value: retu exс_class retu None
Здесь используется функция , которая возвращает набор из информации об обрабатываемом исключении: класса, экземпляра и стека.
Код с использованием этих конструкций будет выглядеть следующим образом:
n = int(input()) try: switch(n) except ( case(1), case(2), case(3) ): print "Число от 1 до 3" except case(4): print "Число 4" except: print "Другое число"