На этом шаге мы рассмотрим использование словарей для имитации конструкции switch ... case.
В Python нет инструкций выбора switch ... case, поэтому иногда в качестве обходного пути возникает необходимость писать цепочки инструкций if ... elif ... else. На этом шаге вы узнаете прием, который сможете применять для имитации инструкций выбора switch ... case в Python при помощи словарей и первоклассных функций. Звучит заманчиво? Отлично, тогда поехали!
Предположим, что в нашей программе есть такая цепочка инструкций if:
if cond == 'cond_a': handle_a() elif cond == 'cond_b': handle_b() else: handle_default()
В случае лишь трех разных условий это, конечно, не так страшно. Но представьте, если бы в этой инструкции у нас было десять или более ответвлений elif. Все стало бы выглядеть немного иначе.
Один из путей преодоления длинных инструкций if ... elif ... else состоит в их замене на таблицы поиска по словарю, которые имитируют поведение инструкций выбора switch ... case.
Мы знаем, что в Python есть функции первого класса. А это означает, что их можно передавать в качестве аргументов в другие функции, возвращать в качестве значений из других функций, присваивать переменным и хранить в структурах данных.
Например, мы можем определить функцию, а затем сохранить ее в списке для доступа к ней в дальнейшем:
>>> def myfunc(a, b): return a + b >>> funcs = [myfunc] >>> funcs[0] <function myfunc at 0x00000195AC7FDDC0>
Синтаксис вызова этой функции работает именно так, как вы интуитивно ожидаете: мы просто обращаемся к списку по индексу и используем вызывной синтаксис "()", чтобы вызвать функцию и передать ей аргументы:
>>> funcs[0](2, 3)
5
Итак, каким же образом мы собираемся использовать функции первого класса, чтобы подрезать нашу цепочечную инструкцию if по размеру? Центральная идея здесь - определить словарь, отображающий ключи поиска входных условий на функции, которые выполнят предназначенные операции:
func_dict = {
'cond_a': handle_a,
'cond_b': handle_b
}
Вместо процеживания сквозь инструкции if, проверяя по ходу каждое условие, мы можем выполнить поиск ключа по словарю, чтобы получить функцию-обработчик, а затем вызвать ее:
>>> cond = 'cond_a'
>>> func_dict[cond]()
Эта реализация уже почти рабочая, по крайней мере, если условие cond можно найти в словаре. Если же его там нет, то мы получим исключение KeyError.
Давайте отыщем способ поддержки случая по умолчанию, который будет соответствовать исходному ответвлению else. К счастью, все словари Python располагают методом get(), который возвращает либо значение по заданному ключу, либо значение по умолчанию, если ключ не может быть найден. Это именно то, что нам здесь и нужно:
>>> func_dict.get(cond, handle_default)()
Поначалу этот фрагмент кода, возможно, будет выглядеть синтаксически странным, но когда вы разложите его по полочкам, то поймете, что он работает в точности как предыдущий пример. Опять-таки, мы используем функции Python первого класса, чтобы передать в поисковый метод get() функцию handle_default в качестве запасного значения. Благодаря этому, если условие в словаре не может быть найдено, мы избегаем вызова исключения KeyError и вместо него вызываем заданную по умолчанию функцию-обработчик.
На следующем шаге мы закончим изучение этого вопроса.