Оператор switch-case — это мощная функциональная возможность языка программирования, которая позволяет разработчику управлять ходом выполнения всей программы в зависимости от значения переменной или результата вычисления выражения.

Обычно же эта конструкция языка используется для выполнения различных блоков кода в зависимости от значения некоторой переменной во время выполнения программы. Вот пример использования оператора switch в языке Java.

public static void switch_demo(String[] args) { 
	int month = 8;
	String monthString;
    switch(month) {
    	case 1: monthString = "January";
    		break;
      	case 2: monthString = "February";
           	break;
      	case 3: monthString = "March";
           	break;
      	case 4: monthString = "April";
           	break;      
	  	case 5: monthString = "May";
           	break;      
		case 6: monthString = "June";
           	break; 
		case 7: monthString = "July";
           	break;
		case 8: monthString = "August";
           	break;
		case 9: monthString = "September";
           	break;
 		case 10: monthString = "October";
           	break;           
		case 11: monthString = "November";
           	break;  
  		case 12: monthString = "December";
           	break;
		default: monthString = "Invalid mont";
           	break;
    }
    System.out.println(monthString);
}

Вот как работает этот код:

  1. Компилятор создает таблицу переходов для оператора switch case.
  2. Переменная/выражение в скобках после ключевого слова switch вычисляется один раз.
  3. Оператор switch ищет вычисленное значение переменной/выражения в таблице переходов и после этого непосредственно определяет, какой блок кода выполнить.
  4. Если совпадений не найдено, выполняется код по умолчанию, помещенный в блок кода default.

В приведенном выше примере, в зависимости от значения переменной month, в потоке стандартного вывода будет отображаться соответствующее сообщение. В этом случае, поскольку month = 8, то будет выведено сообщение August.

Оператор switch

И хотя в таких популярных языках, таких как Java и PHP, есть собственный оператор switch, то вы наверное быть удивлены, узнав, что в языке Python его нет. Поэтому у вас, наверняка, уже возникал соблазн написать серию блоков кода if-else-if, используя условный оператор if для каждого значения в case оператора switch.

Тем не менее из-за использования этой таблицы переходов оператор switch работает намного быстрее, чем “лестница” из if-else-if. Вместо того, чтобы последовательно оценивать каждое условие после оператора if, ему нужно только один раз вычислить значение переменной/выражения в switch и непосредственно перейти к соответствующей ветви кода для его выполнения.

Как реализовать оператор switch в Python

Рассмотрим способ реализации оператора switch на языке Python, который заключается в использовании механизма сопоставления словарей. Также этот тип данных более известен как ассоциативные массивы, которые реализуют операцию простого сопоставления «ключ-значение».

В следующем примере мы создаем словарь switcher, который будет хранить все значения, помещаемые после ключевого слова case.

def switch_demo(argument):
	switcher = {
		1: "January",
		2: "February",
    	3: "March",
    	4: "April",
    	5: "May",
    	6: "June",
    	7: "July",
    	8: "August",
    	9: "September",
    	10: "October",
    	11: "November",
    	12: "December"
}
print switcher.get(argument, "Invalid month")

В приведенном выше примере, когда вы передаете значение в качестве аргумента функции switch_demo, оно сопоставляется с ключами словаря switcher. И если совпадение будет найдено, то в терминале будет выведено связанное с ним значение (месяц), в противном случае печатается строка по умолчанию «Invalid month». Строка по умолчанию помогает реализовать инструкцию default case оператора switch.

Сопоставление ключей словаря для функций

Теперь становится интереснее. Как известно, значениями словаря Python могут быть данные любого типа. Таким образом, нам не нужно ограничиваться использованием констант (целых чисел, строк), мы можем использовать в качестве значений словаря как имена функций, так и лямбда-выражения.

Теперь с учетом вышесказанного, мы можем переписать наш пример реализации оператора switch, используя словарь с именами функций, используемых в качестве значений. В данном случае switch – это словарь имён функций, а не строк.

def one():
	return "January"
	
def two():
	return "February"

def three():
	return "March"
	
def four():
	return "April"
	
def five():
	return "May"

def six():
	return "June"
	
def seven():
	return "July"
	
def eight():
	return "August"
	
def nine():
	return "September"
	
def ten():
	return "October"
	
def eleven():
	return "November"
	
def twelve():
	return "December"
	
def numbers_to_months(argument):
	switcher = {
    	1: one,
    	2: two,
    	3: three,
    	4: four,
    	5: five,
    	6: six,
    	7: seven,
    	8: eight,
    	9: nine,
    	10: ten,
    	11: eleven,
    	12: twelve
  	}
# Получим функцию из словаря switcher
func = switcher.get(argument, lambda: "Invalid month")
# Вызовем полученную функцию
print func()

Хотя указанные выше функции довольно просты и возвращают только строки, вы можете использовать этот подход для выполнения более сложных блоков кода внутри каждой функции.

Фактически, если вы вызываете методы для объектов, вы даже можете использовать специальный метод для диспетчеризации, чтобы динамически определять, какую функцию нужно вызывать во время выполнения.

class Switcher(object):
	def numbers_to_months(self, argument):
    	"""Dispatch method"""
    	method_name = 'month_' + str(argument)
    	# Получим соответствующий метод у объекта self. По умолчанию передадим lambda функцию.
    	method = getattr(self, method_name, lambda: "Invalid month")
    	# Вызовем метод и вернем его результат
    	return method()
    
    	def month_1(self):
    		return "January"
    
    	def month_2(self):
    		return "February"
    
    	def month_3(self):
    		return "March"
    
    ...

Исходя из значения переданного аргумента нативная функция getattr() будет возвращать методы объекта с определенным именем.

Input: a=Switcher()
Input: a.numbers_to_months(1)
Output: January

Преимущество подхода Python для реализации switch

Поскольку можно изменять словари Python во время выполнения кода: то есть добавлять, удалять или обновлять их элементы, а точнее пары ключ-значение. То можно легко изменить сам оператор switch в процессе выполнения программы, как говориться “на лету”. Рассмотрим следующий пример кода:

def zero():
	return "zero"
	
def one():
	return "one"

def two():
	return "two"

switcher = {
	0: zero,
    1: one,
    2: two
}

def numbers_to_strings(argument):
  # Получим функцию из словаря switcher
  func = switcher.get(argument, "nothing")
  # вызовем соответствующую функции
  return func()

Результатом его выполнения будет вывод следующих значений в терминале.





Input: numbers_to_strings(1)
Output: One
    
Input: switcher[1]=two # тут мы изменили поведение для определенного case в switcher 
Input: numbers_to_strings(1)
Output: Two

Switch-case — очень полезная конструкция кода, которая не только обеспечивает лучшую производительность, чем использование последовательности операторов if-else, но и предоставляет разработчику более управляемый и гибкий код. Если вы почувствовали себя ограниченным в своих действия из-за отсутствия оператора switch в Python, надеюсь, эта статья поможет реализовать его в ваших программах.

Оставить комментарий