Шаг 167.
Python: тонкости программирования.
Трюки со словарем. Имитация инструкций выбора на основе словарей

    На этом шаге мы рассмотрим использование словарей для имитации конструкции 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 и вместо него вызываем заданную по умолчанию функцию-обработчик.

    На следующем шаге мы закончим изучение этого вопроса.




Предыдущий шаг Содержание Следующий шаг