Я хочу написать функцию в Python, которая возвращает различные фиксированные значения в зависимости от значения входного индекса.
В других языках я бы использовал оператор switch
или case
, но в Python, похоже, нет switch
оператора. Каковы рекомендуемые решения Python в этом сценарии?
python
switch-statement
Майкл Шнайдер
источник
источник
switch
на самом деле является более «универсальным», чем то, что возвращает разные фиксированные значения, основанные на значении входного индекса. Это позволяет выполнять разные части кода. На самом деле даже не нужно возвращать значение. Интересно, являются ли некоторые ответы здесь хорошей заменой для общегоswitch
утверждения или только для случая возврата значений без возможности выполнения общих частей кода.Ответы:
Вы можете использовать словарь:
источник
get
метода, вероятно, будет более нормальным, чем использованиеcollections.defaultdict
в этом случае.}.get(x, default)
вместо этого, если должно быть значение по умолчанию. (Примечание: это намного лучше, чем то, что происходит, если вы оставите значение по умолчанию выключенным оператором switch!)Если вы хотите использовать значения по умолчанию, вы можете использовать
get(key[, default])
метод словаря :источник
Мне всегда нравилось делать это так
Отсюда
источник
.get()
(как текущие самые высокие ответы), должны будут с нетерпением оценить все возможности перед отправкой, и поэтому не только (не только очень, но) чрезвычайно неэффективны и также не могут иметь побочных эффектов; этот ответ обходит эту проблему, но более многословен. Я бы просто использовал if / elif / else, и даже те, которые пишутся так же, как «case», занимают столько же времени.[value]
, который будет возвращать только одну из 3 функций (при условии, чтоvalue
это один из 3 ключей). Эта функция еще не была вызвана. Затем(x)
вызывает только что возвращенную функцию сx
аргументом as (и результат отправляется вresult
). Другие 2 функции не будут вызваны.В дополнение к методам словаря (которые мне действительно нравятся, кстати, вы также можете использовать
if
-elif
-else
для полученияswitch
/case
/default
функциональности:Это, конечно, не идентично переключению / случаю - вы не можете иметь провал так же легко, как пропустить
break
утверждение, но у вас может быть более сложный тест. Его форматирование лучше, чем ряд вложенныхif
s, хотя функционально это то, к чему оно ближе.источник
get
способе, но стандартный способ просто более читабелен.x = the.other.thing
до. Как правило, у вас будет один if, несколько elif и еще один, поскольку это легче понять.if/elif/else
?x in 'bc'
, имейте в виду, что"" in "bc"
это такTrue
.Мой любимый рецепт Python для switch / case:
Коротко и просто для простых сценариев.
Сравните с 11+ строками кода C:
Вы даже можете назначить несколько переменных с помощью кортежей:
источник
default = -1; result = choices.get(key, default)
.result=key=='a'?1:key==b?2:-1
result = 1 if key == 'a' else (2 if key == 'b' else 'default')
. но читается ли один вкладыш?Применение:
тесты:
источник
if
утверждение?case(2)
блок вызвал другую функцию, которая использует switch (), то при выполнении командыcase(2, 3, 5, 7)
etc для поиска следующего выполняемого случая он будет использовать значение switch, установленное другой функцией, а не значение, установленное текущим оператором switch. ,Мой любимый рецепт действительно хороший . Вам действительно понравится. Это самый близкий из тех, что я видел в реальных операторах переключения, особенно в функциях.
Вот пример:
источник
for case in switch()
сwith switch() as case
, имеет больше смысла, так как это нужно с , чтобы запустить только один раз.with
это неbreak
учитывает, поэтому опцию отмены.if c in set(range(0,9)): print "digit" elif c in set(map(chr, range(ord('a'), ord('z')))): print "lowercase"
?источник
value
свойства в класс Switch, чтобы вы могли ссылаться на негоcase.value
внутри оператора.Есть шаблон, который я узнал из кода Twisted Python.
Вы можете использовать его в любое время, когда вам нужно отправить токен и выполнить расширенный фрагмент кода. В конечном автомате у вас были бы
state_
методы и отправка поself.state
. Этот ключ можно легко расширить, унаследовав от базового класса и определив ваши собственныеdo_
методы. Часто у вас даже не будетdo_
методов в базовом классе.Редактировать: как именно это используется
В случае SMTP вы будете получать
HELO
с провода. Соответствующий код (отtwisted/mail/smtp.py
, измененный для нашего случая) выглядит следующим образомВы получите
' HELO foo.bar.com '
(или вы можете получить'QUIT'
или'RCPT TO: foo'
). Это обозначеноparts
как['HELO', 'foo.bar.com']
. Фактическое имя поиска метода взято изparts[0]
.(Исходный метод также вызывается
state_COMMAND
, потому что он использует тот же шаблон для реализации конечного автомата, т.е.getattr(self, 'state_' + self.mode)
)источник
Допустим, вы не хотите просто возвращать значение, но хотите использовать методы, которые что-то изменяют в объекте. Использование подхода, изложенного здесь, будет:
Здесь происходит то, что python оценивает все методы в словаре. Таким образом, даже если ваше значение равно «a», объект будет увеличиваться и уменьшаться на x.
Решение:
Таким образом, вы получите список, содержащий функцию и ее аргументы. Таким образом, только указатель функции и список аргументов будут возвращены, а не оценены. Затем «результат» оценивает возвращенный вызов функции.
источник
Я просто собираюсь бросить свои два цента здесь. Причина, по которой в Python нет оператора case / switch, заключается в том, что Python следует принципу «есть только один правильный способ сделать что-то». Очевидно, что вы могли бы придумать различные способы воссоздания функциональности switch / case, но Pythonic способ сделать это - конструкция if / elif. т.е.
Я просто чувствовал, что PEP 8 заслуживает одобрения. Одна из прекрасных особенностей Python - это его простота и элегантность. Это во многом основано на принципах, заложенных в PEP 8, в том числе «Есть только один правильный способ сделать что-то»
источник
развивая идею «диктуй как переключатель». если вы хотите использовать значение по умолчанию для вашего коммутатора:
источник
'default'
) из правила (получить что-то из этого диктата). По замыслу, программы на Python используют исключения без промедления. При этом использованиеget
может потенциально сделать код немного приятнее.Если у вас сложный блок case, вы можете рассмотреть возможность использования таблицы поиска словаря функций ...
Если вы еще этого не сделали, неплохо было бы зайти в ваш отладчик и посмотреть, как словарь ищет каждую функцию.
Примечание: не используйте «()» в случае / поиск в словаре , или он будет вызывать каждый из ваших функций , как создается словарь / корпус блока. Запомните это, потому что вы хотите вызывать каждую функцию только один раз, используя поиск в хэш-стиле.
источник
Если вы ищете дополнительный оператор как «switch», я создал модуль python, расширяющий Python. Это называется ESPY как «Улучшенная структура для Python» и доступен как для Python 2.x, так и для Python 3.x.
Например, в этом случае оператор switch может быть выполнен с помощью следующего кода:
это можно использовать так:
так espy перевести его в Python как:
источник
while True:
в верхней части сгенерированного кода Python? Он неизбежно попадетbreak
в конец сгенерированного кода Python, поэтому мне кажется, чтоwhile True:
иbreak
можно удалить. Кроме того, достаточно ли ESPY умен, чтобы изменить имя,cont
если пользователь использует это же имя в своем собственном коде? В любом случае, я хочу использовать ванильный Python, поэтому я не буду его использовать, но, тем не менее, это круто. +1 за чистую крутость.while True:
иbreak
s заключается в том, чтобы разрешить, но не требовать провала .Я обнаружил, что общая структура переключателя:
может быть выражено в Python следующим образом:
или отформатирован более четко:
Вместо выражения версия Python является выражением, которое оценивается как значение.
источник
parameter
иp1==parameter
f = lambda x: 'a' if x==0 else 'b' if x==1 else 'c'
. Когда я позже позвонилf(2)
, я получил'c'
;f(1)
,'b'
; иf(0)
,'a'
. Что касается p1 (x), он обозначает предикат; пока он возвращаетTrue
илиFalse
, независимо от того, является ли это вызовом функции или выражением, это нормально.Большинство ответов здесь довольно старые, особенно принятые, поэтому, кажется, стоит обновить.
Во-первых, официальный FAQ по Python охватывает это и рекомендует
elif
цепочку для простых случаев иdict
для больших или более сложных случаев. Он также предлагает наборvisit_
методов (стиль, используемый многими серверными платформами) для некоторых случаев:В FAQ также упоминается PEP 275 , который был написан, чтобы получить официальное разовое решение о добавлении операторов переключения в стиле C. Но этот PEP был фактически отложен до Python 3, и он был официально отклонен только как отдельное предложение, PEP 3103 . Ответ был, конечно, нет - но у двух PEP есть ссылки на дополнительную информацию, если вас интересуют причины или история.
Одна вещь, которая возникала несколько раз (и это можно увидеть в PEP 275, даже если это было вырезано как реальная рекомендация), заключается в том, что если вам действительно надоело иметь 8 строк кода для обработки 4 случаев по сравнению с 6 строки, которые вы бы имели в C или Bash, вы всегда можете написать так:
Это не совсем воодушевляет PEP 8, но он читабелен и не слишком однотипен.
За более чем десятилетие, с тех пор как PEP 3103 был отклонен, вопрос о заявлениях в стиле C или даже о более мощной версии в Go считался мертвым; всякий раз, когда кто-нибудь поднимает вопрос о python-ideas или -dev, они обращаются к старому решению.
Однако идея полного сопоставления с образцом в стиле ML возникает каждые несколько лет, особенно после того, как такие языки, как Swift и Rust, приняли ее. Проблема состоит в том, что трудно получить много пользы от сопоставления с образцом без алгебраических типов данных. Хотя Гвидо сочувствовал этой идее, никто не выдвинул предложение, которое очень хорошо вписывается в Python. (Вы можете прочитать моего соломенного человека 2014 года для примера.) Это может измениться
dataclass
в 3.7 и некоторых спорадических предложениях для более мощныхenum
для обработки типов сумм, или с различными предложениями для различных видов привязок локальных операторов (таких как PEP 3150 или множество предложений, обсуждаемых в настоящее время на -иде). Но пока это не так.Также иногда появляются предложения по сопоставлению в стиле Perl 6, что, по сути, является путаницей всего, от
elif
регулярных выражений до однократного переключения типов.источник
Решение для запуска функций:
где foo1 (), foo2 (), foo3 () и default () являются функциями
источник
foo2()
, функцииfoo1()
,foo3()
иdefault()
и все также будут работать, а это значит, что все может занять много времениget(option)()
. задача решена.Я не нашел ни одного простого ответа в поиске в Google. Но я все равно понял это. Это действительно довольно просто. Решил опубликовать это, и, возможно, предотвратить несколько меньше царапин на голове другого человека. Ключ просто "в" и кортежи. Вот поведение оператора switch при переходе через RANDOM.
Обеспечивает:
источник
break
в конце кода для acase
. Но я думаю, что нам не нужен такой «прорыв» :)Решения, которые я использую:
Здесь размещена комбинация из двух решений, которые относительно легко читаются и поддерживают значения по умолчанию.
где
смотрит
"lambda x: x - 2"
в диктанте и использует его сx=23
не находит его в dict и использует значение по умолчанию
"lambda x: x - 22"
сx=44
.источник
источник
источник
Мне понравился ответ Марка Биса
Поскольку
x
переменная должна использоваться дважды, я изменил лямбда-функции на параметры.Я должен бежать с
results[value](value)
Изменить: я заметил, что я могу использовать
None
тип с словарями. Так что это будет подражатьswitch ; case else
источник
result[None]()
?result = {'a': 100, None:5000}; result[None]
None:
ведет себя какdefault:
.Короткий и легкий для чтения, имеет значение по умолчанию и поддерживает выражения как в условиях, так и в возвращаемых значениях.
Однако это менее эффективно, чем решение со словарем. Например, Python должен просмотреть все условия, прежде чем вернуть значение по умолчанию.
источник
Вы можете использовать отправленный dict:
Вывод:
источник
Простой, не проверенный; Каждое условие оценивается независимо: не существует никакого провала, но оцениваются все случаи (хотя включаемое выражение оценивается только один раз), если только нет оператора break. Например,
печатает
Was 1. Was 1 or 2. Was something.
(Черт возьми! Почему у меня не может быть конечных пробелов во встроенных блоках кода?), еслиexpression
вычисляется как1
,Was 2.
еслиexpression
оценивается2
, илиWas something.
еслиexpression
вычисляется что-то еще.источник
Определение:
позволяет вам использовать довольно простой синтаксис, с вариантами, связанными в карту:
Я продолжал пытаться переопределить переключение таким образом, чтобы я мог избавиться от «лямбды:», но сдался. Настройка определения:
Позволил мне сопоставить несколько случаев с одним и тем же кодом и предоставить параметр по умолчанию:
Каждый реплицированный случай должен быть в своем собственном словаре; switch () объединяет словари перед поиском значения. Это все еще более уродливо, чем мне бы хотелось, но оно имеет базовую эффективность использования хешированного поиска в выражении, а не цикла по всем ключам.
источник
Я думаю, что лучший способ - использовать идиомы языка Python, чтобы ваш код был тестируемым . Как было показано в предыдущих ответах, я использую словари, чтобы использовать в своих интересах структуры и язык python и держу код "case" изолированным различными методами. Ниже есть класс, но вы можете использовать непосредственно модуль, глобальные переменные и функции. В классе есть методы, которые можно тестировать изолированно . В зависимости от ваших потребностей, вы также можете играть со статическими методами и атрибутами.
Можно воспользоваться этим методом, используя также классы в качестве ключей "__choice_table". Таким образом, вы можете избежать злоупотреблений и содержать все в чистоте и проверять.
Предположим, вам нужно обработать много сообщений или пакетов из сети или вашего MQ. Каждый пакет имеет свою собственную структуру и свой код управления (в общем). С помощью приведенного выше кода можно сделать что-то вроде этого:
Таким образом, сложность не распространяется в потоке кода, а отображается в структуре кода .
источник
Расширяя ответ Грега Хьюгилла - Мы можем инкапсулировать словарь-решение, используя декоратор:
Это может быть использовано с
@case
-decoratorХорошей новостью является то, что это уже было сделано в модуле NeoPySwitch . Просто установите используя pip:
источник
Решение, которое я склонен использовать, которое также использует словари:
Преимущество этого состоит в том, что он не пытается оценивать функции каждый раз, и вам просто нужно убедиться, что внешняя функция получает всю информацию, которая нужна внутренним функциям.
источник
До сих пор было много ответов, в которых говорилось: «У нас нет переключателя в Python, сделайте это так». Тем не менее, я хотел бы отметить, что сам оператор switch является легко злоупотребляемой конструкцией, которую можно и нужно избегать в большинстве случаев, потому что она способствует ленивому программированию. Дело в точке:
Теперь вы могли бы сделать это с помощью оператора switch (если бы Python предлагал его), но вы бы тратили время впустую, потому что есть методы, которые делают это просто отлично. Или, может быть, у вас есть что-то менее очевидное:
Однако такого рода операции можно и нужно выполнять с помощью словаря, поскольку он будет быстрее, менее сложным, менее подверженным ошибкам и более компактным.
И подавляющее большинство «вариантов использования» для операторов switch попадет в один из этих двух случаев; просто очень мало причин использовать его, если вы тщательно продумали свою проблему.
Итак, вместо того, чтобы спрашивать «как я могу переключиться в Python?», Возможно, нам следует спросить: «почему я хочу переключиться в Python?» потому что это часто более интересный вопрос и часто выявляет недостатки в дизайне всего, что вы строите.
Нельзя сказать, что переключатели никогда не должны использоваться. Конечные автоматы, лексеры, парсеры и автоматы все в некоторой степени используют их, и, в общем, когда вы начинаете с симметричного входа и переходите к асимметричному выходу, они могут быть полезны; вам просто нужно убедиться, что вы не используете переключатель в качестве молотка, потому что вы видите кучу гвоздей в своем коде.
источник