Замена оператора switch в Python?

Я хочу написать функцию на Python, которая возвращает разные фиксированные значения в зависимости от значения входного индекса.

На других языках я бы использовал инструкцию switch или case, но в Python, похоже, нет инструкции switch. Какие решения Python рекомендуются в этом сценарии?

Связанный PEP, созданный самим Гвидо: PEP 3103

chb 16.06.2012 21:22

@chb В этом PEP Гвидо не упоминает, что цепочки if / elif также являются классическим источником ошибок. Это очень хрупкая конструкция.

itsbruce 09.01.2014 17:46

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

Bob Stein 17.10.2014 23:04

switch на самом деле более «универсален», чем что-то, возвращающее различные фиксированные значения на основе значения входного индекса. Это позволяет выполнять разные фрагменты кода. На самом деле даже не нужно возвращать значение. Интересно, являются ли некоторые из ответов здесь хорошей заменой для общего оператора switch или только для случая возврата значений без возможности выполнения общих фрагментов кода.

sancho.s ReinstateMonicaCellio 15.05.2017 00:29

@ sancho.s - согласился. Если вы не вернетесь или не прервете выполнение инструкции switchcase, то в остальных случаях будет выполнен код все. Это явно не то же самое, что набор if / elseifs

BrynJ 25.08.2017 12:01

@ MalikA.Rumi Хрупкая конструкция, точно так же, как цикл while - хрупкая конструкция, если вы попытаетесь использовать его для того, что ... в ... делает. Вы собираетесь называть программистов слабыми в использовании циклов for? В то время как петли - это все, что им действительно нужно. Но циклы for демонстрируют четкое намерение, сохраняют бессмысленный шаблон и дают возможность создавать мощные абстракции.

itsbruce 01.10.2017 09:53

Таким же образом синтаксис вроде Ruby case ... when ... (или Scala match, Haskell's case, Perl given / when) соответствует общему варианту использования и предлагает мощную абстракцию. если ... элиф ... плохая замена.

itsbruce 01.10.2017 10:14

@itsbruce: Мне мало о Haskell или Ruby, и вообще ничего о Perl и Scala, поэтому нам придется пока прекратить эти дебаты, но я не могу не чувствовать, что это мнение больше, чем факт. Хотя может быть весело и интересно. Ваше здоровье.

Malik A. Rumi 01.10.2017 13:39

Афоризм Python о том, что «явное лучше, чем неявное», делает провал в Python нестандартным. Не знаю, грустить мне или радоваться: |

John Strood 09.07.2018 11:24
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1 717
9
1 716 344
44
Перейти к ответу Данный вопрос помечен как решенный

Ответы 44

Ответ принят как подходящий

Вы можете использовать словарь:

def f(x):
    return {
        'a': 1,
        'b': 2,
    }[x]

Что произойдет, если x не будет найден?

Nick 19.09.2008 19:46

@nick: вы можете использовать defaultdict

Eli Bendersky 19.09.2008 21:38

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

Claudiu 23.10.2008 20:22

@EliBendersky, использование метода get, вероятно, было бы более нормальным, чем использование collections.defaultdict в этом случае.

Mike Graham 23.02.2012 20:38

@Nick, выдается исключение - делай }.get(x, default) вместо него, если должен быть дефолт. (Примечание: это намного лучше, чем то, что произойдет, если вы оставите значение по умолчанию выключенным в инструкции switch!)

Mike Graham 23.02.2012 20:39

жаль, что нет поддержки переключателя / корпуса. Я просто использую операторы if, поскольку предпочитаю, чтобы логика была простой для других и для себя, если я пересмотрю свой код долгое время (и забуду этот потрясающий ответ @Greg Hewgilland и @Nick)

Ross 02.03.2012 04:13

Словарь, реализующий переключатель, также можно использовать в качестве значения функции по умолчанию. Таким образом, он так же эффективен, как и Клаудиу, упомянутый в вышеприведенном комментарии, но по-прежнему является локальным для функции. Проблема в том, что кто-то пытается передать аргумент словаря, который не предназначен для использования извне :) Жизнь полна компромиссов.

pepr 14.07.2012 20:05

Я не могу заставить его работать должным образом при использовании оператора print внутри словаря. ideone.com/aL9EUE

Anderson Green 11.08.2013 20:54

@AndersonGreen: Это другая проблема. Этот вопрос задан по поводу возврата «фиксированных значений». Вам придется использовать другое решение, если вы хотите использовать print (потому что print имеет побочные эффекты, и весь словарь оценивается при его создании).

Greg Hewgill 12.08.2013 00:18

@GregHewgill К счастью, кто-то уже нашел решение: stackoverflow.com/a/11479840/975097

Anderson Green 12.08.2013 00:30

Когда вы создаете для этого большой словарь и хотите провалиться, это пригодится: stackoverflow.com/a/2974151/724752

David Winiecki 12.09.2014 19:42

Вы также можете просто использовать someDict.getitem(x) или, что еще лучше, someDict[x].

jpaugh 03.12.2015 02:08

Это лучший ответ на языке каждый, всегда используйте хэш (словарь, ассоциативный массив), он более чистый, чем другие варианты

boctulus 01.06.2016 22:11

@pepr: в Python 3 с PEP 3102 вы можете избежать риска случайного изменения аргумента по умолчанию, используя аргументы, содержащие только ключевые слова, например def f(x, *, _lookup = {'a': 1, 'b': 2}): return _lookup.get(x, 3). * без имени означает, что аргументы после этой точки могут передаваться только по имени, поэтому вызов f(1, {}) не приведет к неправильному поведению. Пользователь мог сделать f(1, _lookup = {}), но это его вина. Префиксы подчеркивания обычно означают «только для внутреннего использования», и мы все здесь взрослые; если они хотят игнорировать это правило, это их прерогатива.

ShadowRanger 03.06.2016 20:46

Конечно, в этом ограниченном случае вам даже не нужна функция уровня Python, вы можете просто привязать методы dict напрямую, например, без случая по умолчанию, f = {'a': 1, 'b': 2}.__getitem__, или со значением по умолчанию, f = collections.defaultdict(lambda: 3, {'a': 1, 'b': 2}).__getitem__ (хотя последний будет хранить автоматически оживленные пары ключ / значение, поэтому здесь имеет смысл использовать функцию-оболочку, чтобы этого избежать).

ShadowRanger 03.06.2016 20:53

Можете ли вы включить пример того, как будет использоваться этот оператор псевдопереключения?

Stevoisiak 01.02.2018 22:08

Это общее решение не только для Python, но и для языка в целом. Я не думаю, что люди понимают реальные варианты использования коммутаторов.

Woody1193 31.08.2018 01:21

Как мне это назвать в Python?

Ben 16.10.2019 10:01

Если действия нетривиальны, вы можете сделать значения словаря функциями и вызывать соответствующий (таблица прыжков / переходов); кто-нибудь хочет опубликовать пример?

Mawg says reinstate Monica 11.02.2020 08:53

вы можете использовать совпадение рано или поздно: stackoverflow.com/questions/59098889/…

sailfish009 24.08.2020 06:55

x10 неэффективно по сравнению с цепочкой if

roberto 20.11.2020 12:15

синтаксис соответствия был принят и скоро будет официально поддерживаться в python 3!

Mathieu Rollet 26.02.2021 17:50

Мне всегда нравилось так делать

result = {
  'a': lambda x: x * 5,
  'b': lambda x: x + 7,
  'c': lambda x: x - 2
}[value](x)

Отсюда

отличный метод в сочетании с get () для обработки по умолчанию - тоже мой лучший выбор

drAlberT 02.09.2009 20:11

Он просит фиксированные значения. Зачем создавать функцию для вычисления чего-либо, когда это поиск? Однако интересное решение для других проблем.

Nick 21.01.2010 20:06

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

Asher 23.04.2012 01:48

К сожалению, это самое близкое, что может случиться с людьми. Методы, которые используют .get() (например, текущие самые высокие ответы), должны будут тщательно оценить все возможности перед отправкой, и поэтому они не только (не только очень, но) чрезвычайно неэффективны, но и не могут иметь побочных эффектов; этот ответ обходит эту проблему, но более подробен. Я бы просто использовал if / elif / else, и даже их написание занимает столько же времени, сколько и case.

ninjagecko 17.03.2014 17:48

не будет ли это оценивать все функции / лямбды каждый раз во всех случаях, даже если он возвращает только один из результатов?

slf 06.08.2014 23:04

Что делать, если вам нужно провалить корпус?

StartupGuy 08.08.2014 03:39

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

hamsolo474 - Reinstate Monica 05.04.2015 09:43

@slf Нет, когда поток управления достигает этого фрагмента кода, он построит 3 функции (с использованием 3 лямбда-выражений), а затем создаст словарь с этими 3 функциями в качестве значений, но они останутся невызванными (оценивать немного неоднозначен в этот контекст) сначала. Затем словарь индексируется через [value], который возвращает только одну из трех функций (при условии, что value является одним из трех ключей). Функция еще не вызывалась. Затем (x) вызывает только что возвращенную функцию с x в качестве аргумента (и результат переходит к result). Остальные 2 функции не будут вызваны.

blubberdiblub 18.09.2015 09:11

@blubberdiblub ах, поэтому он будет каждый раз создавать все функции, но оценивать только одну из них

slf 18.09.2015 14:44

@slf Да, именно так и происходит. Хотел бы я сказать это так же коротко, как вы;)

blubberdiblub 18.09.2015 16:09

Не для фиксированных значений, а для дорогостоящих функций (время, память и т. д.) Это предпочтительнее, поскольку лямбда-выражения не будут оцениваться во время построения словаря. +1 к комментарию @blubberdiblub за разъяснение этого вопроса.

dojuba 22.05.2018 17:50

@ninjagecko, как вы думаете, почему использование get заставляет любой словарь оценивать все значения - это не так. get ищет ключ - результат O (1), а затем, если ключ не существует, возвращает значение по умолчанию - это не хуже, чем: if key in dict: return dict [key] else: return default

Tony Suffolk 66 04.06.2018 15:22

@ TonySuffolk66: Вы неправильно поняли мою формулировку; нет такой вещи, как dict, переоценивающий свои значения (которые уже вычислены в неленивом питоне). Я только что сказал, что ответы, которые создают словарь и вызывают .get - чтобы напрямую вернуть значение - должны были уже вычислить эти значения. Вы не должны писать {True:f(), False:g()}[x] (O (f + g)) вместо f() if x else g() (O (max (f, g))). Единственное преимущество - OP запрашивает фиксированные значения, но это доказывает, что нельзя заменить оператор switch на {...} / .get sans lambda, если вы заботитесь об асимптотике. Конечно, накладные расходы на вызов функций тоже плохи.

ninjagecko 05.06.2018 16:47

@ninjagecko - я понимаю, о чем вы говорите - просто ваш комментарий предполагал (ну, как я его читал), что использование get вызывает дополнительную проблему - и я был озадачен.

Tony Suffolk 66 06.06.2018 19:34

Вам нужно только построить этот словарь однажды: result = { <dict of lambdas> }, а затем вызвать его с помощью result[val](x). Тогда это становится очень эффективным решением.

Dave Rove 15.09.2019 10:10

Можно ли использовать лямбды с разными параметрами? Т.е. случай 'a' мог иметь lambda x: 2*x, случай 'b' иметь lambda x, y: x + y, случай 'c' иметь lambda y: 2*y ...

abrac 12.12.2020 23:09

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

О, и если вам хочется сделать что-то вроде переключателя, см. здесь.

В дополнение к словарным методам (которые мне очень нравятся, кстати) вы также можете использовать if-elif-else для получения функциональности switch / case / default:

if x == 'a':
    # Do the thing
elif x == 'b':
    # Do the other thing
if x in 'bc':
    # Fall-through by not using elif, but now the default case includes case 'a'!
elif x in 'xyz':
    # Do yet another thing
else:
    # Do the default

Это, конечно, не идентично переключателю / случаю - у вас не может быть провала так же легко, как отказ от оператора break, но вы можете пройти более сложный тест. Его форматирование лучше, чем у серии вложенных if, хотя функционально он ближе к нему.

Я бы предпочел это, он использует стандартную языковую конструкцию и не генерирует KeyError, если соответствующий регистр не найден

martyglaubitz 18.05.2013 14:30

Я думал о словарном способе / get, но стандартный способ просто более читабельный.

Martin Thoma 25.06.2015 09:33

Не совсем работает как оператор switch, но очень близко. На мой взгляд самое близкое

Arijoon 26.08.2015 23:37

Это самое чистое решение. Чаще всего у каждого switch есть break, и наиболее распространенное использование провала, которое я вижу, - это сопоставление нескольких элементов, как в if x in 'bc':.

bmacnaughton 30.12.2015 19:32

Но переменная x повторяется несколько раз. Если вам нужно заменить x, это намного проще с помощью оператора switch / case. Кроме того, если / elif / else дает вам слишком много свободы (как показано в примере выше, при смешивании == и in, условия могут перекрываться, и это становится трудно читать.

some user 29.02.2016 21:58

@someuser, но то, что они могут "перекрываться", - это особенность. Вы просто убедитесь, что порядок соответствует приоритету, в котором должны происходить совпадения. Что касается повторного x: просто сделайте x = the.other.thing раньше. Как правило, у вас будет один if, несколько elif и один else, поскольку это легче понять.

Matthew Schinckel 03.03.2016 09:55

Кроме того, не обязательно, чтобы к x каждый раз применялся один и тот же тип теста. т.е. == vs in vs not in или что-то еще.

Matthew Schinckel 03.03.2016 09:57

@Matthew: Проще говоря, если вам нужна такая гибкость, вы используете if/elif/else. Но большинство из тех, кто посещает эту тему, этого не делают. Нам нужен более структурный код. Любой язык, поддерживающий switch, уже поддерживает if/elif/else.

some user 04.03.2016 00:33

Приятно, однако, «провал из-за неиспользования elif» немного сбивает с толку. А как насчет этого: забыть о «провале» и принять это как два if/elif/else?

Alois Mahdal 30.05.2016 14:40

Также стоит упомянуть, что при использовании таких вещей, как x in 'bc', имейте в виду, что "" in "bc" - это True.

Lohmar ASHAR 28.08.2018 14:46

Это действительно ответ. Конечно, вы можете создать словарную конструкцию, но if/elif является наиболее понятным.

Armstrongest 02.04.2019 00:33

Это, вероятно, самый хрупкий способ разработки этой конструкции, особенно с использованием провалов таким образом, который не является интуитивно понятным и дублирует код.

user-63873687 25.05.2020 14:36

@ user-63873687 Да, я не писал сквозной код (который, я согласен, очень хрупкий). Интересно, есть ли способ убрать мое имя из ответа, потому что мне действительно не нравится этот шаблон: я сам сейчас неправильно его прочитал.

Matthew Schinckel 26.05.2020 02:28

Кажется более традиционным, чем все остальное. Словари добавляют гибкости выбора и повторного использования, но для небольших случаев не имеют смысла.

vintproykt 14.06.2020 10:32

Также стоит упомянуть, что вы можете написать if x = 'a': action = 'foo'; result = fn(action) в одной строке без необходимости использования новой строки и отступа. Это может сделать блоки if else более краткими и более похожими на оператор case.

James McGuigan 22.12.2020 03:18

Есть шаблон, который я узнал из кода Twisted Python.

class SMTP:
    def lookupMethod(self, command):
        return getattr(self, 'do_' + command.upper(), None)
    def do_HELO(self, rest):
        return 'Howdy ' + rest
    def do_QUIT(self, rest):
        return 'Bye'

SMTP().lookupMethod('HELO')('foo.bar.com') # => 'Howdy foo.bar.com'
SMTP().lookupMethod('QUIT')('') # => 'Bye'

Вы можете использовать его в любое время, когда вам нужно отправить токен и выполнить расширенный фрагмент кода. В конечном автомате у вас будут методы state_ и отправка на self.state. Этот переключатель можно полностью расширить, унаследовав от базового класса и определив свои собственные методы do_. Часто у вас даже не будет методов do_ в базовом классе.

Обновлено: как именно это используется

В случае SMTP вы получите HELO по сети. Соответствующий код (из twisted/mail/smtp.py, модифицированный для нашего случая) выглядит так

class SMTP:
    # ...

    def do_UNKNOWN(self, rest):
        raise NotImplementedError, 'received unknown command'

    def state_COMMAND(self, line):
        line = line.strip()
        parts = line.split(None, 1)
        if parts:
            method = self.lookupMethod(parts[0]) or self.do_UNKNOWN
            if len(parts) == 2:
                return method(parts[1])
            else:
                return method('')
        else:
            raise SyntaxError, 'bad syntax'

SMTP().state_COMMAND('   HELO   foo.bar.com  ') # => Howdy foo.bar.com

Вы получите ' HELO foo.bar.com ' (или можете получить 'QUIT' или 'RCPT TO: foo'). Это токенизируется в parts как ['HELO', 'foo.bar.com']. Фактическое имя поиска метода взято из parts[0].

(Исходный метод также называется state_COMMAND, потому что он использует тот же шаблон для реализации конечного автомата, то есть getattr(self, 'state_' + self.mode))

Я не вижу преимуществ этого шаблона по сравнению с прямым вызовом методов: SMTP (). Do_HELO ('foo.bar.com') Хорошо, в lookupMethod может быть общий код, но поскольку он также может быть перезаписан подкласс Я не вижу, что вы получите от косвенного обращения.

Mr Shark 13.09.2008 15:35

Вы не знаете, какой метод вызвать заранее, то есть «HELO» исходит от переменной. я добавил пример использования в исходный пост

user6205 13.09.2008 21:45

Могу я предложить просто: eval ('SMTP (). Do_' + command) ('foo.bar.com')

jforberg 21.06.2011 21:32

Кроме того, зачем создавать новый объект SMTP для каждого вызова метода? Вот для чего нужны глобальные функции.

jforberg 21.06.2011 21:34

eval? серьезно? и вместо того, чтобы создавать экземпляр одного метода для каждого вызова, мы вполне можем создать экземпляр один раз и использовать его во всех вызовах, если он не имеет внутреннего состояния.

Mahesh 19.03.2013 22:10

ИМО, настоящий ключ здесь - это отправка с использованием getattr для указания функции для запуска. Если бы методы были в модуле, вы могли бы получить их с помощью getattr (locals (), func_name). Часть 'do_' хороша для безопасности / ошибок, поэтому могут быть вызваны только функции с префиксом. Сам SMTP вызывает lookupMethod. В идеале внешний мир ни о чем из этого не знает. На самом деле нет смысла делать SMTP (). LookupMethod (name) (data). Поскольку команда и данные находятся в одной строке, и SMTP анализирует их, это имеет больше смысла. Наконец, SMTP, вероятно, имеет другое общее состояние, которое оправдывает его принадлежность к классу.

ShawnFumo 16.08.2013 02:17

Этот метод тревожит. На самом деле, просто используйте dict. Нет нужды в этой навороченной чепухе с getattr.

connectyourcharger 17.05.2019 13:30

расширяя идею «диктовать как переключатель». если вы хотите использовать для своего переключателя значение по умолчанию:

def f(x):
    try:
        return {
            'a': 1,
            'b': 2,
        }[x]
    except KeyError:
        return 'default'

Я думаю, что проще использовать .get () в dict со значением по умолчанию. Я предпочитаю оставлять исключения для исключительных обстоятельств, и это сокращает три строки кода и уровень отступа, не делая его непонятным.

Chris B. 05.06.2009 19:14

Это является исключительное обстоятельство. Это может быть или не быть обстоятельством редкий в зависимости от полезности, но это определенно исключение (возврат к 'default') из правила (получите что-то из этого dict). По задумке программы Python используют исключения сразу же. При этом использование get потенциально может немного улучшить код.

Mike Graham 26.03.2010 19:49

Если вам нужны значения по умолчанию, вы можете использовать метод словаря get(key[, default]):

def f(x):
    return {
        'a': 1,
        'b': 2
    }.get(x, 9)    # 9 is default if x not found

Что, если «a» и «b» соответствуют 1, а «c» и «d» соответствуют 2?

John Mee 09.04.2010 11:57

@JM: Очевидно, поиск по словарю не поддерживает провалы. Вы можете выполнить двойной поиск по словарю. Т.е. 'a' и 'b' указывают на answer1, а 'c' и 'd' указывают на answer2, которые содержатся во втором словаре.

Nick 09.04.2010 13:54

лучше передать значение по умолчанию

HaTiMSuM 13.10.2016 14:01

У этого подхода есть проблемы: сначала каждый раз, когда вы вызываете f, вы собираетесь снова создавать dict, во-вторых, если у вас более сложное значение, вы можете получить исключения ex. если x - кортеж, и мы хотим сделать что-то вроде этого x = ('a') def f (x): return {'a': x [0], 'b': x [1]} .get ( x [0], 9) Это вызовет IndexError

Idan Haim Shalom 30.08.2017 11:01

@Idan: Вопрос был в репликации коммутатора. Я уверен, что смогу сломать и этот код, если попробую ввести нечетные значения. Да, воссоздадут, но исправить это несложно.

Nick 20.09.2017 00:59

Решения, которые я использую:

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

result = {
  'a': lambda x: x * 5,
  'b': lambda x: x + 7,
  'c': lambda x: x - 2
}.get(whatToUse, lambda x: x - 22)(value)

куда

.get('c', lambda x: x - 22)(23)

ищет "lambda x: x - 2" в dict и использует его с x=23

.get('xxx', lambda x: x - 22)(44)

не находит его в dict и использует "lambda x: x - 22" по умолчанию с x=44.

Допустим, вы не хотите просто возвращать значение, а хотите использовать методы, которые что-то меняют в объекте. Использование изложенного здесь подхода будет:

result = {
  'a': obj.increment(x),
  'b': obj.decrement(x)
}.get(value, obj.default(x))

Здесь происходит то, что python оценивает все методы в словаре. Таким образом, даже если ваше значение равно «a», объект получит увеличенное значение и, уменьшенное на x.

Решение:

func, args = {
  'a' : (obj.increment, (x,)),
  'b' : (obj.decrement, (x,)),
}.get(value, (obj.default, (x,)))

result = func(*args)

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

Если вы ищете extra-statement, например, «switch», я создал модуль python, расширяющий Python. Он называется ESPY как «Расширенная структура для Python» и доступен как для Python 2.x, так и для Python 3.x.

Например, в этом случае оператор switch может быть выполнен с помощью следующего кода:

macro switch(arg1):
    while True:
        cont=False
        val=%arg1%
        socket case(arg2):
            if val==%arg2% or cont:
                cont=True
                socket
        socket else:
            socket
        break

который можно использовать так:

a=3
switch(a):
    case(0):
        print("Zero")
    case(1):
        print("Smaller than 2"):
        break
    else:
        print ("greater than 1")

так что переводите это на Python как:

a=3
while True:
    cont=False
    if a==0 or cont:
        cont=True
        print ("Zero")
    if a==1 or cont:
        cont=True
        print ("Smaller than 2")
        break
    print ("greater than 1")
    break

Очень круто, но какой смысл в while True: в верхней части сгенерированного кода Python? Он неизбежно попадет в break в нижней части сгенерированного кода Python, поэтому мне кажется, что и while True:, и break могут быть удалены. Кроме того, достаточно ли умен ESPY, чтобы изменить имя cont, если пользователь использует то же имя в своем собственном коде? В любом случае, я хочу использовать ванильный Python, поэтому я не буду его использовать, но тем не менее это круто. +1 за чистую прохладу.

ArtOfWarfare 29.06.2014 16:56

@ArtOfWarfare Причина для while True: и breaks состоит в том, чтобы позволить, но не требовать провал.

Solomon Ucko 23.03.2019 17:10

Этот модуль еще доступен?

Solomon Ucko 24.03.2019 03:57

class switch(object):
    value = None
    def __new__(class_, value):
        class_.value = value
        return True

def case(*args):
    return any((arg == switch.value for arg in args))

Использование:

while switch(n):
    if case(0):
        print "You typed zero."
        break
    if case(1, 4, 9):
        print "n is a perfect square."
        break
    if case(2):
        print "n is an even number."
    if case(2, 3, 5, 7):
        print "n is a prime number."
        break
    if case(6, 8):
        print "n is an even number."
        break
    print "Only single-digit numbers are allowed."
    break

Тесты:

n = 2
#Result:
#n is an even number.
#n is a prime number.
n = 11
#Result:
#Only single-digit numbers are allowed.

Это небезопасно. Если несколько переключателей задействованы одновременно, все переключатели принимают значение последнего переключателя.

francescortiz 26.06.2013 20:35

Хотя @francescortiz, вероятно, означает потокобезопасность, это также небезопасно. Это угрожает значениям переменных!

Zizouz212 16.06.2015 19:29

Проблема безопасности потоков, вероятно, может быть решена с помощью локальное хранилище потока. Или этого можно было бы вообще избежать, вернув экземпляр и используя этот экземпляр для сравнения случаев.

blubberdiblub 18.09.2015 09:24

@blubberdiblub Но разве не более эффективно использовать стандартный оператор if?

wizzwizz4 23.05.2016 20:32

Переключатель @ wizzwizz4 может возвращать функцию: case=switch( foo ), если он более эффективен, чем указанный выше (или вы имеете в виду меньше ввода)

Jasen 24.08.2016 00:59

@Jasen Думаю, я имел в виду набор текста, потому что мы уже знаем, что if будет быстрее.

wizzwizz4 24.08.2016 12:02

Кажется, что здесь не происходит нормального провального поведения операторов switch (если только предыдущие случаи не указаны явно, как в примере), что может вводить в заблуждение.

Grayscale 02.08.2017 21:53

Это также небезопасно при использовании в нескольких функциях. В приведенном примере, если блок case(2) вызвал другую функцию, которая использует switch (), то при выполнении case(2, 3, 5, 7) и т. д. Для поиска следующего случая для выполнения он будет использовать значение switch, установленное другой функцией, а не то, которое установлено текущей оператор переключения.

user9876 17.08.2017 11:58

- 1, это не потокобезопасно и не может быть вызвано рекурсивно. Я серьезно надеюсь, что вы, ребята, этого не сделаете.

Navin 11.07.2018 22:22

Использование глобальной переменной модуля для отслеживания локального состояния - ужасная идея. Что происходит, когда логика switch case вызывает функцию, которая также использует switch? switch.value будет перезаписан, что приведет к нарушению обработки последующих случаев! Ниже представлена ​​гораздо лучшая реализация этого подхода., и люди должны проголосовать против этого ответа и проголосовать за него.

Alex Coventry 14.09.2018 18:41

Fallthrough можно было бы более чисто реализовать, используя в вашем классе переменную Fallthrough, которая устанавливается при вызове switch () и может установить для следующего вызова значение true. Например: "select.fallthrough = select.fallthrough или любой ((arg == switch.value для arg в args))" "return select.fallthrough" Затем при тестировании варианта (2, 3, 5, 7) вы можете пропустить «2», и он все равно сработает.

user-63873687 25.05.2020 14:42

Этот метод тоже неэффективен. Есть два вложенных цикла, и словари лучше, чем цикл for.

Joël V. 19.06.2020 18:22

Мой любимый - действительно хороший рецепт приготовления. Это самый близкий из тех, что я видел, к реальным операторам switch case, особенно в функциях.

class switch(object):
    def __init__(self, value):
        self.value = value
        self.fall = False

    def __iter__(self):
        """Return the match method once, then stop"""
        yield self.match
        raise StopIteration
    
    def match(self, *args):
        """Indicate whether or not to enter a case suite"""
        if self.fall or not args:
            return True
        elif self.value in args: # changed for v1.5, see below
            self.fall = True
            return True
        else:
            return False

Вот пример:

# The following example is pretty much the exact use-case of a dictionary,
# but is included for its simplicity. Note that you can include statements
# in each suite.
v = 'ten'
for case in switch(v):
    if case('one'):
        print 1
        break
    if case('two'):
        print 2
        break
    if case('ten'):
        print 10
        break
    if case('eleven'):
        print 11
        break
    if case(): # default, could also just omit condition or 'if True'
        print "something else!"
        # No need to break here, it'll stop anyway

# break is used here to look as much like the real thing as possible, but
# elif is generally just as good and more concise.

# Empty suites are considered syntax errors, so intentional fall-throughs
# should contain 'pass'
c = 'z'
for case in switch(c):
    if case('a'): pass # only necessary if the rest of the suite is empty
    if case('b'): pass
    # ...
    if case('y'): pass
    if case('z'):
        print "c is lowercase!"
        break
    if case('A'): pass
    # ...
    if case('Z'):
        print "c is uppercase!"
        break
    if case(): # default
        print "I dunno what c was!"

# As suggested by Pierre Quentel, you can even expand upon the
# functionality of the classic 'case' statement by matching multiple
# cases in a single shot. This greatly benefits operations such as the
# uppercase/lowercase example above:
import string
c = 'A'
for case in switch(c):
    if case(*string.lowercase): # note the * for unpacking as arguments
        print "c is lowercase!"
        break
    if case(*string.uppercase):
        print "c is uppercase!"
        break
    if case('!', '?', '.'): # normal argument passing style also applies
        print "c is a sentence terminator!"
        break
    if case(): # default
        print "I dunno what c was!"

В некоторых комментариях указывалось, что решение диспетчера контекста, использующее with foo as case, а не for case in foo, может быть более чистым, и для больших операторов switch может быть приятным штрихом линейное, а не квадратичное поведение. Частью значения этого ответа с циклом for является возможность иметь разрывы и провалы, и если мы хотим немного поиграть с нашим выбором ключевых слов, мы можем получить это также в диспетчере контекста:

class Switch:
    def __init__(self, value):
        self.value = value
        self._entered = False
        self._broken = False
        self._prev = None

    def __enter__(self):
        return self

    def __exit__(self, type, value, traceback):
        return False # Allows a traceback to occur

    def __call__(self, *values):
        if self._broken:
            return False
        
        if not self._entered:
            if values and self.value not in values:
                return False
            self._entered, self._prev = True, values
            return True
        
        if self._prev is None:
            self._prev = values
            return True
        
        if self._prev != values:
            self._broken = True
            return False
        
        if self._prev == values:
            self._prev = None
            return False
    
    @property
    def default(self):
        return self()

Вот пример:

# Prints 'bar' then 'baz'.
with Switch(2) as case:
    while case(0):
        print('foo')
    while case(1, 2, 3):
        print('bar')
    while case(4, 5):
        print('baz')
        break
    while case.default:
        print('default')
        break

Я бы заменил for case in switch() на with switch() as case, это имеет больше смысла, поскольку он должен запускаться только один раз.

Ski 12.12.2013 20:24

@Skirmantas: Обратите внимание, что with не поддерживает break, поэтому возможность пропадания отсутствует.

Jonas Schäfer 08.05.2014 20:53

Приносим извинения за то, что не приложили больше усилий, чтобы определить это сам: аналогичный ответ выше не является потокобезопасным. Это?

David Winiecki 12.09.2014 19:47

@DavidWiniecki Компоненты кода, отсутствующие в приведенном выше (и, возможно, авторское право activestate), кажутся потокобезопасными.

Jasen 24.08.2016 01:09

была бы другая версия этого типа if c in set(range(0,9)): print "digit" elif c in set(map(chr, range(ord('a'), ord('z')))): print "lowercase"?

mpag 31.10.2016 22:08

Если у вас сложный блок case, вы можете рассмотреть возможность использования таблицы поиска словаря функций ...

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

ПРИМЕЧАНИЕ. Используйте нет "()" внутри поиска по регистру / словарю, иначе он вызовет каждую из ваших функций при создании блока словаря / регистра. Помните об этом, потому что вы хотите вызывать каждую функцию только один раз, используя поиск в стиле хеша.

def first_case():
    print "first"

def second_case():
    print "second"

def third_case():
    print "third"

mycase = {
'first': first_case, #do not use ()
'second': second_case, #do not use ()
'third': third_case #do not use ()
}
myfunc = mycase['first']
myfunc()

Мне нравится ваше решение. Но что, если мне просто нужно передать некоторые переменные или объекты?

Tedo Vrbanec 19.12.2018 23:27

Это не сработает, если метод ожидает параметры.

Kulasangar 29.01.2020 09:35

Это метод, который официально рекомендуется в FAQ по Python.

Cestarian 18.10.2020 22:43

def f(x):
     return 1 if x == 'a' else\
            2 if x in 'bcd' else\
            0 #default

Короткий и удобный для чтения, имеет значение по умолчанию и поддерживает выражения как в условиях, так и в возвращаемых значениях.

Однако он менее эффективен, чем решение со словарем. Например, Python должен просмотреть все условия, прежде чем вернуть значение по умолчанию.

Простое сопоставление некоторого ключа с некоторым кодом на самом деле не является проблемой, как показало большинство людей, используя dict. Настоящая уловка состоит в том, чтобы подражать всему, что происходит «насквозь». Не думаю, что когда-либо писал case-выражение, в котором я использовал бы эту «особенность». Вот вам шанс.

def case(list): reduce(lambda b, f: (b | f[0], {False:(lambda:None),True:f[1]}[b | f[0]]())[0], list, False)

case([
    (False, lambda:print(5)),
    (True, lambda:print(4))
])

Я действительно представлял это как единое утверждение. Надеюсь, вы простите глупое форматирование.

reduce(
    initializer=False,
    function=(lambda b, f:
        ( b | f[0]
        , { False: (lambda:None)
          , True : f[1]
          }[b | f[0]]()
        )[0]
    ),
    iterable=[
        (False, lambda:print(5)),
        (True, lambda:print(4))
    ]
)

Надеюсь, это правильный питон. Это должно дать вам пропасть. конечно, логические проверки могут быть выражениями, и если вы хотите, чтобы они вычислялись лениво, вы можете заключить их все в лямбду. Мне было бы несложно заставить его принять после выполнения некоторых пунктов в списке. Просто создайте кортеж (bool, bool, function), где второй bool указывает, следует ли прерывать или пропускать.

Drop-through неструктурирован. Вам это не нужно, это затруднит поддержку вашего кода, сложнее избежать ошибок, и он запрещен многими моими стандартами кодирования. Это пережиток C. C не стал на 100% структурированным, он остался в drop-through, goto, continue, break. Большинство его потомков скопировали его.

ctrl-alt-delor 11.02.2013 14:34

также используйте Список для хранения дел и вызовите соответствующую функцию, выбрав-

cases = ['zero()','one()','two()','three()']

def zero():
  print "method for 0 called..."
def one():
  print "method for 1 called..."
def two():
  print "method for 2 called..."
def three():
  print "method for 3 called..." 

i = int(raw_input("Enter choice between 0-3 "))

if (i<=len(cases)):
 exec(cases[i])
else:
 print "wrong choice"

также объяснено в винтовой стол

зачем использовать exec, если вы можете хранить объекты функций в списке, а не в списке строк?

Jean-François Fabre 25.05.2019 22:33

Определение:

def switch1(value, options):
  if value in options:
    options[value]()

позволяет использовать довольно простой синтаксис, когда кейсы объединены в карту:

def sample1(x):
  local = 'betty'
  switch1(x, {
    'a': lambda: print("hello"),
    'b': lambda: (
      print("goodbye," + local),
      print("!")),
    })

Я продолжал пытаться переопределить переключатель таким образом, чтобы он позволил мне избавиться от «лямбда:», но сдался. Настройка определения:

def switch(value, *maps):
  options = {}
  for m in maps:
    options.update(m)
  if value in options:
    options[value]()
  elif None in options:
    options[None]()

Позволил мне сопоставить несколько случаев с одним и тем же кодом и указать вариант по умолчанию:

def sample(x):
  switch(x, {
    _: lambda: print("other") 
    for _ in 'cdef'
    }, {
    'a': lambda: print("hello"),
    'b': lambda: (
      print("goodbye,"),
      print("!")),
    None: lambda: print("I dunno")
    })

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

Я не нашел простого ответа, который искал нигде в поиске Google. Но я все равно разобрался. Это действительно очень просто. Решил выложить, а может помешать еще несколько царапин на чужой голове. Ключ просто «in» и кортежи. Вот поведение оператора switch при провале, включая случайный провал.

l = ['Dog', 'Cat', 'Bird', 'Bigfoot',
     'Dragonfly', 'Snake', 'Bat', 'Loch Ness Monster']

for x in l:
    if x in ('Dog', 'Cat'):
        x += " has four legs"
    elif x in ('Bat', 'Bird', 'Dragonfly'):
        x += " has wings."
    elif x in ('Snake',):
        x += " has a forked tongue."
    else:
        x += " is a big mystery by default."
    print(x)

print()

for x in range(10):
    if x in (0, 1):
        x = "Values 0 and 1 caught here."
    elif x in (2,):
        x = "Value 2 caught here."
    elif x in (3, 7, 8):
        x = "Values 3, 7, 8 caught here."
    elif x in (4, 6):
        x = "Values 4 and 6 caught here"
    else:
        x = "Values 5 and 9 caught in default."
    print(x)

Обеспечивает:

Dog has four legs
Cat has four legs
Bird has wings.
Bigfoot is a big mystery by default.
Dragonfly has wings.
Snake has a forked tongue.
Bat has wings.
Loch Ness Monster is a big mystery by default.

Values 0 and 1 caught here.
Values 0 and 1 caught here.
Value 2 caught here.
Values 3, 7, 8 caught here.
Values 4 and 6 caught here
Values 5 and 9 caught in default.
Values 4 and 6 caught here
Values 3, 7, 8 caught here.
Values 3, 7, 8 caught here.
Values 5 and 9 caught in default.

Где именно здесь провал?

Jonas Schäfer 08.05.2014 20:56

Ой! Там есть провалы, но я больше не участвую в Stack Overflow. ИХ вообще не нравятся. Мне нравится вклад других, но только не Stackoverflow. Если вы используете провал для ФУНКЦИОНАЛЬНОСТИ, тогда вы хотите уловить определенные условия во всех в одном операторе case в переключателе (catch all), пока вы не дойдете до оператора break в переключателе.

JD Graham 30.07.2014 08:58

Здесь оба значения «Собака» и «Кошка» ПАДАЮТ НА ПРОСМОТР и обрабатываются ОДНОЙ функциональностью, то есть они определены как имеющие «четыре ноги». Это АБСТРАКТНЫЙ эквивалент провала и разные значения, обрабатываемые ТО ЖЕ оператором case, когда происходит разрыв.

JD Graham 30.07.2014 09:16

@JDGraham Я думаю, что Джонас имел в виду еще один аспект провала, который случается, когда программист иногда забывает написать break в конце кода для case. Но думаю, нам не нужен "провал" такой :)

Mikhail Batcer 12.08.2015 12:00

Понравился Ответ Марка Биса

Поскольку переменная x должна использоваться дважды, я изменил лямбда-функции на без параметров.

Я должен работать с results[value](value)

In [2]: result = {
    ...:   'a': lambda x: 'A',
    ...:   'b': lambda x: 'B',
    ...:   'c': lambda x: 'C'
    ...: }
    ...: result['a']('a')
    ...: 
Out[2]: 'A'

In [3]: result = {
    ...:   'a': lambda : 'A',
    ...:   'b': lambda : 'B',
    ...:   'c': lambda : 'C',
    ...:   None: lambda : 'Nothing else matters'

    ...: }
    ...: result['a']()
    ...: 
Out[3]: 'A'

Редактировать: Я заметил, что могу использовать тип None со словарями. Таким образом, это будет эмулировать switch ; case else

Разве случай None не эмулирует просто result[None]()?

Bob Stein 11.03.2015 18:19

Да, точно. Я имею ввиду result = {'a': 100, None:5000}; result[None]

guneysus 11.03.2015 18:52

Просто проверяю, что никто не думает, что None: ведет себя как default:.

Bob Stein 11.03.2015 19:54

Я обнаружил, что общая структура переключателей:

switch ...parameter...
case p1: v1; break;
case p2: v2; break;
default: v3;

можно выразить в Python следующим образом:

(lambda x: v1 if p1(x) else v2 if p2(x) else v3)

или отформатировать более четко:

(lambda x:
     v1 if p1(x) else
     v2 if p2(x) else
     v3)

Версия Python - это не выражение, а выражение, которое вычисляет значение.

Также вместо ... параметра ... и p1 (x) как насчет parameter и p1==parameter

Bob Stein 11.03.2015 18:28

@ BobStein-VisiBone привет, вот пример, который выполняется в моем сеансе Python: 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, независимо от того, является ли это вызовом функции или выражением, все в порядке.

leo 13.03.2015 19:16

@ BobStein-VisiBone Да, вы правы! Спасибо :) Чтобы многострочное выражение работало, следует заключить круглые скобки, как в вашем предложении, или как в моем модифицированном примере.

leo 14.03.2015 08:16

Отлично. Теперь я удалить все мои комментарии про паренсы.

Bob Stein 14.03.2015 23:48

class Switch:
    def __init__(self, value):
        self.value = value

    def __enter__(self):
        return self

    def __exit__(self, type, value, traceback):
        return False # Allows a traceback to occur

    def __call__(self, *values):
        return self.value in values


from datetime import datetime

with Switch(datetime.today().weekday()) as case:
    if case(0):
        # Basic usage of switch
        print("I hate mondays so much.")
        # Note there is no break needed here
    elif case(1,2):
        # This switch also supports multiple conditions (in one line)
        print("When is the weekend going to be here?")
    elif case(3,4):
        print("The weekend is near.")
    else:
        # Default would occur here
        print("Let's go have fun!") # Didn't use case for example purposes

Использование контекстных менеджеров - хорошее творческое решение. Я бы порекомендовал добавить небольшое объяснение и, возможно, ссылку на некоторую информацию о менеджерах контекста, чтобы дать этому посту некоторый, ну, контекст;)

Will 03.05.2015 12:13

Мне не очень нравятся цепочки if / elif, но это и самое креативное, и самое практичное из всех решений, которые я видел с использованием существующего синтаксиса Python.

itsbruce 02.10.2017 11:05

Это действительно здорово. Одно из предлагаемых улучшений - добавить (общедоступное) свойство value к классу Switch, чтобы вы могли ссылаться на case.value в операторе.

Peter 24.01.2019 14:03

Этот ответ предоставляет наиболее функциональные возможности переключателя, хотя и довольно прост. Проблема с использованием dict заключается в том, что вы можете только получать данные и не можете запускать функции / методы.

moshevi 05.10.2020 18:55

Python> = 3.10 (предварительная версия)

Ух ты, Python теперь получает настоящий синтаксис match / case!

PEP 634, 'структурное сопоставление с образцом'; a.k.a. switch / case, был одобрен и добавлен в Python 3.10.

Пример использования:

match something:
    case 0 | 1 | 2:
        print("Small number")
    case [] | [_]:
        print("A short sequence")
    case str() | bytes():
        print("Something string-like")
    case _:
        print("Something else")

Python <= 3.9

Мой любимый рецепт переключателя / корпуса на Python был:

choices = {'a': 1, 'b': 2}
result = choices.get(key, 'default')

Коротко и просто для простых сценариев.

Сравните с 11+ строками кода C:

// C Language version of a simple 'switch/case'.
switch( key ) 
{
    case 'a' :
        result = 1;
        break;
    case 'b' :
        result = 2;
        break;
    default :
        result = -1;
}

Вы даже можете назначить несколько переменных, используя кортежи:

choices = {'a': (1, 2, 3), 'b': (4, 5, 6)}
(result1, result2, result3) = choices.get(key, ('default1', 'default2', 'default3'))

Я считаю, что это более надежный ответ, чем принятый.

cerd 19.08.2015 02:16

Обратите внимание, что 2 сегмента кода не совпадают. Версия python возвращает значение по умолчанию, если совпадений нет, но версия C возвращает -1. Когда вы заменяете строку на choices.get(key, -1), ее становится труднее читать, потому что людям приходится делать паузу, чтобы подумать, как работает get () и что означает -1.

some user 29.02.2016 22:05

@some user: C требует, чтобы возвращаемое значение было одного и того же типа для всех случаев. Python этого не делает. Я хотел выделить эту гибкость Python на тот случай, если у кого-то возникнет ситуация, которая потребует такого использования.

ChaimG 01.03.2016 03:17

@some user: Лично я нахожу {} .get (,) читабельным. Для дополнительной читабельности для начинающих Python вы можете использовать default = -1; result = choices.get(key, default).

ChaimG 01.03.2016 03:19

сравните с 1 строкой C++ result=key=='a'?1:key==b?2:-1

Jasen 24.08.2016 01:01

@Jasen можно утверждать, что вы можете сделать это и в одной строке Python: result = 1 if key == 'a' else (2 if key == 'b' else 'default'). но читается ли один лайнер?

ChaimG 24.08.2016 05:57

@ChaimG tbh C one liner довольно читаем в этих простых случаях

Valen 06.06.2017 14:22

Дополнительным преимуществом этого подхода является более четкое разделение кода и данных. Это упрощает передачу данных в качестве параметра (упрощает задачу написания тестов) или, например, перемещение их в файл конфигурации.

Peter 11.09.2017 18:37

Такова проблема сравнения языков по тому, сколько строк нужно, чтобы выразить идею. Обычно вы можете выполнить что-то в Python с помощью одной строки, и вы можете всегда выразить что-то с помощью одной строки в C.

Rakurai 06.01.2020 17:51

обратите внимание, что вам не хватает функций, которые считаются присущими операторам switch, например, провал

user-63873687 25.05.2020 14:38

этот подход каждый раз выделяет память для словаря?

Pranav 01.09.2020 04:37

Этот вопрос касается исключительно Python, а не сравнения Python и C (или C++). У каждого языка есть свои преимущества и недостатки. Практически любой оператор может не выполняться во время выполнения, если не выполняется надлежащая проверка типов, в то время как языки с статической типизацией, поскольку C++ обнаруживает их во время компиляции. С другой стороны, Python включает в себя батареи, с огромным количеством модулей. Можете ли вы назвать любой из языков лучшим?

Akib Azmain 11.01.2021 13:30

# simple case alternative

some_value = 5.0

# this while loop block simulates a case block

# case
while True:

    # case 1
    if some_value > 5:
        print ('Greater than five')
        break

    # case 2
    if some_value == 5:
        print ('Equal to five')
        break

    # else case 3
    print ( 'Must be less than 5')
    break

Думаю, лучший способ - это используйте идиомы языка Python, чтобы ваш код оставался тестируемым. Как показано в предыдущих ответах, я использую словари для воспользоваться преимуществами структур и языка Python и сохраняю "case" код изолированным в разных методах. Ниже приведен класс, но вы можете напрямую использовать модуль, глобальные объекты и функции. В классе есть методы, которые можно протестировать с изоляцией. В зависимости от ваших потребностей вы также можете играть со статическими методами и атрибутами.

class ChoiceManager:

    def __init__(self):
        self.__choice_table = \
        {
            "CHOICE1" : self.my_func1,
            "CHOICE2" : self.my_func2,
        }

    def my_func1(self, data):
        pass

    def my_func2(self, data):
        pass

    def process(self, case, data):
        return self.__choice_table[case](data)

ChoiceManager().process("CHOICE1", my_data)

Можно Воспользуйтесь этим методом, используя также классы в качестве ключей из «__choice_table». Таким образом вы можете избежать это пример злоупотребления и сохранить все в чистоте и тестируемости.

Предположим, вам нужно обработать много сообщений или пакетов из сети или вашего MQ. Каждый пакет имеет свою собственную структуру и свой управляющий код (в общем виде). С помощью приведенного выше кода можно сделать что-то вроде этого:

class PacketManager:

    def __init__(self):
        self.__choice_table = \
        {
            ControlMessage : self.my_func1,
            DiagnosticMessage : self.my_func2,
        }

    def my_func1(self, data):
        # process the control message here
        pass

    def my_func2(self, data):
        # process the diagnostic message here
        pass

    def process(self, pkt):
        return self.__choice_table[pkt.__class__](pkt)

pkt = GetMyPacketFromNet()
PacketManager().process(pkt)


# isolated test or isolated usage example
def test_control_packet():
    p = ControlMessage()
    PacketManager().my_func1(p)

Итак, сложность не распространяется в потоке кода, но отображается в структуре кода.

Действительно некрасиво ... Корпус переключателя такой чистый при чтении. Не могу понять, почему это не реализовано на Python.

jmcollin92 08.04.2016 16:25

@AndyClifton: Мне очень жаль ... пример? Подумайте о каждом случае, когда вам нужно иметь код ветвления с несколькими решениями, и вы можете применить этот метод.

J_Zar 11.04.2016 09:51

@ jmcollin92: оператор switch удобен, я согласен. Однако программист имеет тенденцию писать очень длинные операторы и код, который нельзя использовать повторно. Способ, который я описал, чище для тестирования и более пригоден для повторного использования, ИМХО.

J_Zar 11.04.2016 09:53

@J_Zar: re. Мой запрос на пример: да, я понимаю, но я изо всех сил пытаюсь поместить это в контекст более крупного фрагмента кода. Не могли бы вы показать, как я могу использовать это в реальной ситуации?

Andy Clifton 11.04.2016 12:14

@AndyClifton: Извините, я опоздал, но я опубликовал примерный случай.

J_Zar 20.04.2016 17:56

Если вы не беспокоитесь о потере выделения синтаксиса в наборах case, вы можете сделать следующее:

exec {
    1: """
print ('one')
""", 
    2: """
print ('two')
""", 
    3: """
print ('three')
""",
}.get(value, """
print ('None')
""")

Где value - значение. В C это будет:

switch (value) {
    case 1:
        printf("one");
        break;
    case 2:
        printf("two");
        break;
    case 3:
        printf("three");
        break;
    default:
        printf("None");
        break;
}

Мы также можем создать для этого вспомогательную функцию:

def switch(value, cases, default):
    exec cases.get(value, default)

Таким образом, мы можем использовать это для примера с одним, двумя и тремя:

switch(value, {
    1: """
print ('one')
    """, 
    2: """
print ('two')
    """, 
    3: """
print ('three')
    """,
}, """
print ('None')
""")

Расширение Ответ Грега Хьюджилла - мы можем инкапсулировать словарь-решение с помощью декоратора:

def case(callable):
    """switch-case decorator"""
    class case_class(object):
        def __init__(self, *args, **kwargs):
            self.args = args
            self.kwargs = kwargs

        def do_call(self):
            return callable(*self.args, **self.kwargs)

return case_class

def switch(key, cases, default=None):
    """switch-statement"""
    ret = None
    try:
        ret = case[key].do_call()
    except KeyError:
        if default:
            ret = default.do_call()
    finally:
        return ret

Затем это можно использовать с @case-декоратором.

@case
def case_1(arg1):
    print 'case_1: ', arg1

@case
def case_2(arg1, arg2):
    print 'case_2'
    return arg1, arg2

@case
def default_case(arg1, arg2, arg3):
    print 'default_case: ', arg1, arg2, arg3

ret = switch(somearg, {
    1: case_1('somestring'),
    2: case_2(13, 42)
}, default_case(123, 'astring', 3.14))

print ret

Хорошая новость в том, что это уже было сделано в NeoPySwitch-модуле. Просто установите с помощью pip:

pip install NeoPySwitch

Прочитав ответ, я был весьма сбит с толку, но это все прояснило:

def numbers_to_strings(argument):
    switcher = {
        0: "zero",
        1: "one",
        2: "two",
    }
    return switcher.get(argument, "nothing")

Этот код аналогичен:

function(argument){
    switch(argument) {
        case 0:
            return "zero";
        case 1:
            return "one";
        case 2:
            return "two";
        default:
            return "nothing";
    }
}

Проверьте Источник, чтобы узнать больше о сопоставлении словаря функциям.

Оператор switch - это просто синтаксический сахар для if / elif / else. То, что делает любой управляющий оператор, - это делегирование задания на основе определенного условия, которое выполняется - путь решения. Для включения этого в модуль и возможности вызывать задание на основе его уникального идентификатора можно использовать наследование и тот факт, что любой метод в python является виртуальным, чтобы обеспечить реализацию конкретного задания производного класса, как конкретный обработчик "case"

#!/usr/bin/python

import sys

class Case(object):
    """
        Base class wich specifies the interface for "case" handler.
        The all required arbitrary arguments inside "execute" method will be
        provided through the derived class
        specific constructor

        @note in python, all class methods are virtual
    """
    def __init__(self, id):
        self.id = id

    def pair(self):
        """
            Pairs the given id of the "case" with
            the instance on which "execute" will be called
        """
        return (self.id, self)

    def execute(self):#base class virtual method that needs to be overrided
        pass

class Case1(Case):
    def __init__(self, id, msg):
        self.id = id
        self.msg = msg
    def execute(self):#override the base class method
        print("<Case1> id = {}, message: \"{}\"".format(str(self.id), self.msg))

class Case2(Case):
    def __init__(self, id, n):
        self.id = id
        self.n = n
    def execute(self):#override the base class method
        print("<Case2> id = {}, n = {}.".format(str(self.id), str(self.n)))
        print("\n".join(map(str, range(self.n))))



class Switch(object):
    """
        The class wich delegates the jobs
        based on the given job id
    """
    def __init__(self, cases):
        self.cases = cases#dictionary: time complexitiy for access operation is 1
    def resolve(self, id):

        try:
            cases[id].execute()
        except KeyError as e:
            print("Given id: {} is wrong!".format(str(id)))



if __name__ == '__main__':

    # Cases
    cases=dict([Case1(0, "switch").pair(), Case2(1, 5).pair()])

    switch = Switch(cases)

    # id will be dynamically specified
    switch.resolve(0)
    switch.resolve(1)
    switch.resolve(2)

Я просто брошу сюда свои два цента. Причина, по которой в Python нет оператора case / switch, заключается в том, что Python следует принципу «Есть только один правильный способ что-то сделать». Итак, очевидно, что вы могли бы придумать различные способы воссоздания функциональности переключателя / корпуса, но способ Pythonic для этого - конструкция if / elif. т.е.

if something:
    return "first thing"
elif somethingelse:
    return "second thing"
elif yetanotherthing:
    return "third thing"
else:
    return "default thing"

Я просто почувствовал, что PEP 8 заслуживает одобрения здесь. Одно из прекрасных свойств Python - его простота и элегантность. Это во многом основано на принципах, заложенных в PEP 8, в том числе «Есть только один правильный способ что-то сделать».

Итак, почему в Python есть циклы for и while? Все, что вы можете сделать с помощью цикла for, вы можете реализовать с помощью цикла while.

itsbruce 01.10.2017 13:01

Истинный. Начинающие программисты слишком часто злоупотребляют переключателем / регистром. Что им действительно нужно, так это шаблон стратегии.

user228395 06.10.2017 15:34

Похоже, Python хочет, чтобы это был Clojure

T.W.R. Cole 16.02.2018 08:17

@ T.W.R.Cole: Я так не думаю, Python сделал это первым. Python существует с 1990 года, а Clojure - с 2007 года.

Taylor 09.05.2018 19:52

Есть только один правильный способ что-то сделать. Python 2.7 или Python 3? Ржунимагу.

T.W.R. Cole 23.08.2018 22:09

Очевидно, что принцип дизайна - это не декларация совершенства.

user2233949 24.08.2018 23:55

Цитата из PEP 20, Zen of Python: «Должен быть один - и желательно только один - очевидный способ сделать это».

Solomon Ucko 24.03.2019 03:55

Нет поддержки Fallthru

simpleuser 15.08.2019 04:33

Я сделал реализацию Switch Case, которая не совсем использует ifs извне (она все еще использует if в классе).

class SwitchCase(object):
    def __init__(self):
        self._cases = dict()

    def add_case(self,value, fn):
        self._cases[value] = fn

    def add_default_case(self,fn):
        self._cases['default']  = fn

    def switch_case(self,value):
        if value in self._cases.keys():
            return self._cases[value](value)
        else:
            return self._cases['default'](0)

Используйте это так: -

from switch_case import SwitchCase
switcher = SwitchCase()
switcher.add_case(1, lambda x:x+1)
switcher.add_case(2, lambda x:x+3)
switcher.add_default_case(lambda _:[1,2,3,4,5])

print switcher.switch_case(1) #2
print switcher.switch_case(2) #5
print switcher.switch_case(123) #[1, 2, 3, 4, 5]

Получите повышение производительности, если замените if value in keys блоком try-except.

iBug 27.03.2018 12:00

Следующее работает для моей ситуации, когда мне нужен простой switch-case для вызова кучи методов, а не просто для печати некоторого текста. После игры с лямбдой и глобальными переменными он показался мне самым простым вариантом. Может быть, это и кому-то поможет:

def start():
    print("Start")

def stop():
    print("Stop")

def print_help():
    print("Help")

def choose_action(arg):
    return {
        "start": start,
        "stop": stop,
        "help": print_help,
    }.get(arg, print_help)

argument = sys.argv[1].strip()
choose_action(argument)()  # calling a method from the given string

сделайте закрытие ваших функций действий - т.е. определите их в вашей функции choose_action - и вы также можете получить доступ к любым аргументам и т.д. :-), т.е. это станет моим решением ...

Tony Suffolk 66 06.06.2018 19:51

И еще вариант:

def fnc_MonthSwitch(int_Month): #### Define a function take in the month variable 
    str_Return  = "Not Found"     #### Set Default Value 
    if int_Month==1:       str_Return = "Jan"   
    if int_Month==2:       str_Return = "Feb"   
    if int_Month==3:       str_Return = "Mar"   
    return str_Return;          #### Return the month found  
print ("Month Test 3:  " + fnc_MonthSwitch( 3) )
print ("Month Test 14: " + fnc_MonthSwitch(14) )

Хотя ответов уже достаточно, я хочу указать более простое и мощное решение:

class Switch:
    def __init__(self, switches):
        self.switches = switches
        self.between = len(switches[0]) == 3

    def __call__(self, x):
        for line in self.switches:
            if self.between:
                if line[0] <= x < line[1]:
                    return line[2]
            else:
                if line[0] == x:
                    return line[1]
        return None


if __name__ == '__main__':
    between_table = [
        (1, 4, 'between 1 and 4'),
        (4, 8, 'between 4 and 8')
    ]

    switch_between = Switch(between_table)

    print('Switch Between:')
    for i in range(0, 10):
        if switch_between(i):
            print('{} is {}'.format(i, switch_between(i)))
        else:
            print('No match for {}'.format(i))


    equals_table = [
        (1, 'One'),
        (2, 'Two'),
        (4, 'Four'),
        (5, 'Five'),
        (7, 'Seven'),
        (8, 'Eight')
    ]
    print('Switch Equals:')
    switch_equals = Switch(equals_table)
    for i in range(0, 10):
        if switch_equals(i):
            print('{} is {}'.format(i, switch_equals(i)))
        else:
            print('No match for {}'.format(i))

Выход:

Switch Between:
No match for 0
1 is between 1 and 4
2 is between 1 and 4
3 is between 1 and 4
4 is between 4 and 8
5 is between 4 and 8
6 is between 4 and 8
7 is between 4 and 8
No match for 8
No match for 9

Switch Equals:
No match for 0
1 is One
2 is Two
No match for 3
4 is Four
5 is Five
No match for 6
7 is Seven
8 is Eight
No match for 9

Простой, не проверенный; каждое условие оценивается независимо: нет провала, но оцениваются все случаи (хотя выражение для включения оценивается только один раз), если нет оператора break. Например,

for case in [expression]:
    if case == 1:
        print(end='Was 1. ')

    if case == 2:
        print(end='Was 2. ')
        break

    if case in (1, 2):
        print(end='Was 1 or 2. ')

    print(end='Was something. ')

печатает Was 1. Was 1 or 2. Was something.(Dammit! Why can't I have trailing whitespace in inline code blocks?), если expression оценивается как 1, Was 2., если expression оценивается как 2, или Was something., если expression оценивается как что-то еще.

Ну, провал работает, но только для перехода в do_default.

syockit 28.01.2019 14:17

Решение для запуска функций:

result = {
    'case1':     foo1, 
    'case2':     foo2,
    'case3':     foo3,
}.get(option)(parameters_optional)

где foo1 (), foo2 () и foo3 () - функции

Пример 1 (с параметрами):

option = number['type']
result = {
    'number':     value_of_int,  # result = value_of_int(number['value'])
    'text':       value_of_text, # result = value_of_text(number['value'])
    'binary':     value_of_bin,  # result = value_of_bin(number['value'])
}.get(option)(value['value'])

Пример 2 (без параметров):

option = number['type']
result = {
    'number':     func_for_number, # result = func_for_number()
    'text':       func_for_text,   # result = func_for_text()
    'binary':     func_for_bin,    # result = func_for_bin()
}.get(option)()

Да, например, если ваша переменная option == "case2" ваш результат = foo2 ()

Alejandro Quintanar 21.02.2018 00:27

и так далее.

Alejandro Quintanar 21.02.2018 00:41

Да, я понимаю цель. Но меня беспокоит то, что если вам нужен только foo2(), все функции foo1(), foo3() и default() также будут работать, а это означает, что это может занять много времени.

Brian Underwood 21.02.2018 20:57

Вы совершенно правы, эта простая версия запускает все функции при создании каталога, вы можете решить эту проблему, передав 'option' в качестве параметра функции в foo (), вот рабочий пример: gist.github.com/anonymous/a5ed3953e28440b4368c338b1e19d294

Alejandro Quintanar 22.02.2018 09:10

опустите () внутри словаря. используйте get(option)(). задача решена.

timgeb 10.04.2018 09:00

Отлично, использование () - отличное решение, я постарался проверить его gist.github.com/aquintanar/01e9920d8341c5c6252d507669758fe5

Alejandro Quintanar 17.04.2018 08:13

Я нашел следующий ответ от документы python наиболее полезным:

Вы можете сделать это достаточно легко с помощью последовательности if... elif... elif... else. Было несколько предложений по синтаксису оператора switch, но пока нет единого мнения о том, следует ли и как проводить тесты диапазона. См. PEP 275 для получения полной информации и текущего статуса.

Для случаев, когда вам нужно выбрать из очень большого количества возможностей, вы можете создать словарь, отображающий значения case для вызываемых функций. Например:

def function_1(...):
    ...

functions = {'a': function_1,
             'b': function_2,
             'c': self.method_1, ...}

func = functions[value]
func()

Вызов методов для объектов можно упростить еще больше, используя встроенную функцию getattr () для получения методов с определенным именем:

def visit_a(self, ...):
    ...
...

def dispatch(self, value):
    method_name = 'visit_' + str(value)
    method = getattr(self, method_name)
    method()

Рекомендуется использовать префикс для имен методов, например visit_ в этом примере. Без такого префикса, если значения поступают из ненадежного источника, злоумышленник сможет вызвать любой метод для вашего объекта.

PEP 275, похоже, отклонен.

Peter Mortensen 03.07.2018 12:12

Большинство ответов здесь довольно старые, особенно общепринятые, поэтому кажется, что их стоит обновить.

Во-первых, официальный Python FAQ покрывает это и рекомендует цепочку elif для простых случаев и dict для более крупных или более сложных случаев. Он также предлагает набор методов visit_ (стиль, используемый многими серверными фреймворками) для некоторых случаев:

def dispatch(self, value):
    method_name = 'visit_' + str(value)
    method = getattr(self, method_name)
    method()

В FAQ также упоминается PEP 275, который был написан, чтобы получить официальное раз и навсегда решение о добавлении операторов переключения в стиле C. Но этот PEP был фактически перенесен на Python 3, и он был официально отклонен только как отдельное предложение, PEP 3103. Конечно, ответ был отрицательный, но у двух политиков есть ссылки на дополнительную информацию, если вас интересуют причины или история.


Одна вещь, которая возникала несколько раз (и ее можно увидеть в PEP 275, хотя она была вырезана как реальная рекомендация), заключается в том, что если вас действительно беспокоит наличие 8 строк кода для обработки 4 случаев по сравнению с 6 строки, которые у вас были бы в C или Bash, вы всегда можете написать это:

if x == 1: print('first')
elif x == 2: print('second')
elif x == 3: print('third')
else: print('did not place')

Это не совсем поощряется PEP 8, но это читабельно и не слишком однозначно.


За более чем десятилетие, прошедшее с тех пор, как PEP 3103 был отклонен, проблема операторов case в стиле C или даже немного более мощной версии в Go была признана мертвой; всякий раз, когда кто-то упоминает об этом на python-ideas или -dev, они ссылаются на старое решение.

Однако идея полного сопоставления с образцом в стиле ML возникает каждые несколько лет, особенно после того, как такие языки, как Swift и Rust, приняли ее. Проблема в том, что трудно извлечь пользу из сопоставления с образцом без алгебраических типов данных. Хотя Гвидо с пониманием относился к этой идее, никто не придумал предложения, которое бы хорошо вписывалось в Python. (Вы можете прочитать мой соломенный человек 2014 года в качестве примера.) Это может измениться с dataclass в 3.7 и некоторыми спорадическими предложениями по более мощному enum для обработки типов сумм, или с различными предложениями для различных видов локальных привязок операторов (например, PEP 3150 или set предложений, обсуждаемых в настоящее время по -идеи). Но пока этого не произошло.

Также время от времени появляются предложения о сопоставлении в стиле Perl 6, которое, по сути, представляет собой мешанину всего, от elif до регулярного выражения и переключения типов с одной отправкой.

В качестве незначительного изменения Ответ Марка Бика для необычных случаев, таких как этот дубликат, где у пользователя есть куча вызовов функций для задержки с аргументами для упаковки (и не стоит создавать кучу функций вне очереди) вместо этого :

d = {
    "a1": lambda: a(1),
    "a2": lambda: a(2),
    "b": lambda: b("foo"),
    "c": lambda: c(),
    "z": lambda: z("bar", 25),
    }
return d[string]()

… вы можете сделать это:

d = {
    "a1": (a, 1),
    "a2": (a, 2),
    "b": (b, "foo"),
    "c": (c,)
    "z": (z, "bar", 25),
    }
func, *args = d[string]
return func(*args)

Это конечно короче, но вопрос о том, является ли это более читаемый


Я думаю, что было бы более читабельно (хотя и не короче) переключиться с lambda на partial для этого конкретного использования:

d = {
    "a1": partial(a, 1),
    "a2": partial(a, 2),
    "b": partial(b, "foo"),
    "c": c,
    "z": partial(z, "bar", 25),
    }
return d[string]()

… Который имеет то преимущество, что прекрасно работает и с аргументами ключевого слова:

d = {
    "a1": partial(a, 1),
    "a2": partial(a, 2),
    "b": partial(b, "foo"),
    "c": c,
    "k": partial(k, key=int),
    "z": partial(z, "bar", 25),
    }
return d[string]()

Проблема с этим ответом в том, что все аргументы по-прежнему оцениваются немедленно. Даже если сначала это сработает для пользователя, если однажды ему придется добавить корпус foo(some_expensive_function(3)), это станет проблемой. Либо все ломается, либо им приходится отдельно проверять этот случай перед словарем, что не только выглядит странно, но и может ввести в заблуждение читателя, который с первого взгляда подумает, что единственные варианты, которые следует учитывать, находятся в словаре.

Alex Hall 04.06.2018 22:39

@AlexHall Когда у вас есть кусок произвольного кода, который нужно отложить, а не просто вызов функции, который нужно отложить, вам действительно нужно обернуть его функцией. И для чего-то менее тривиального, чем игрушечный пример, который вы только что привели, это, вероятно, даже не лямбда, а вне очереди с именем def, которое вам нужно. Но я не думаю, что это недостаток языка или что-то в этом роде, потому что такой код действительно не является - и не должен быть - распространенным. Если у вас есть более реалистичный пример, вероятно, есть лучший способ его реорганизовать.

abarnert 04.06.2018 22:49

Вы правы, мой пример можно решить, просто написав lambda: foo(some_expensive_function(3)) для этого случая. Я добавил мой собственный ответ по этим строкам.

Alex Hall 04.06.2018 23:24

Подобно этот ответ от abarnert, вот решение специально для случая использования вызова одной функции для каждого «случая» в коммутаторе, избегая при этом lambda или partial для сверхкороткости, но при этом имея возможность обрабатывать аргументы ключевого слова:

class switch(object):
    NO_DEFAULT = object()

    def __init__(self, value, default=NO_DEFAULT):
        self._value = value
        self._result = default

    def __call__(self, option, func, *args, **kwargs):
        if self._value == option:
            self._result = func(*args, **kwargs)
        return self

    def pick(self):
        if self._result is switch.NO_DEFAULT:
            raise ValueError(self._value)

        return self._result

Пример использования:

def add(a, b):
    return a + b

def double(x):
    return 2 * x

def foo(**kwargs):
    return kwargs

result = (
    switch(3)
    (1, add, 7, 9)
    (2, double, 5)
    (3, foo, bar=0, spam=8)
    (4, lambda: double(1 / 0))  # if evaluating arguments is not safe
).pick()

print(result)

Обратите внимание, что это вызовы цепочки, то есть switch(3)(...)(...)(...). Не ставьте запятые между ними. Также важно поместить все это в одно выражение, поэтому я использовал дополнительные круглые скобки вокруг основного вызова для неявного продолжения строки.

Приведенный выше пример вызовет ошибку, если вы включите значение, которое не обрабатывается, например switch(5)(1, ...)(2, ...)(3, ...). Вместо этого вы можете указать значение по умолчанию, например switch(5, default=-1)... возвращает -1.

Решение, которое я обычно использую, в котором также используются словари:

def decision_time( key, *args, **kwargs):
    def action1()
        """This function is a closure - and has access to all the arguments"""
        pass
    def action2()
        """This function is a closure - and has access to all the arguments"""
        pass
    def action3()
        """This function is a closure - and has access to all the arguments"""
        pass

   return {1:action1, 2:action2, 3:action3}.get(key,default)()

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

Легко вспомнить:

while True:
    try:
        x = int(input("Enter a numerical input: "))
    except:
        print("Invalid input - please enter a Integer!");
    if x==1:
        print("good");
    elif x==2:
        print("bad");
    elif x==3:
        break
    else:
        print ("terrible");

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

def ToUpper(lcChar):
    if (lcChar == 'a' or lcChar == 'A'):
        return 'A'
    elif (lcChar == 'b' or lcChar == 'B'):
        return 'B'
    ...
    elif (lcChar == 'z' or lcChar == 'Z'):
        return 'Z'
    else:
        return None        # or something

Теперь вы мог делаете это с помощью оператора switch (если Python предлагал его), но вы зря потратите время, потому что есть методы, которые отлично справляются с этим. Или, может быть, у вас есть что-то менее очевидное:

def ConvertToReason(code):
    if (code == 200):
        return 'Okay'
    elif (code == 400):
        return 'Bad Request'
    elif (code == 404):
        return 'Not Found'
    else:
        return None

Однако такого рода операции можно и нужно обрабатывать со словарем, потому что они будут быстрее, менее сложными, менее подверженными ошибкам и более компактными.

И подавляющее большинство «вариантов использования» операторов switch попадает в один из этих двух случаев; просто очень мало причин использовать его, если вы тщательно обдумали свою проблему.

Итак, вместо того, чтобы спрашивать «как мне переключиться на Python?», Возможно, мы должны спросить: «почему я хочу переключиться на Python?» потому что это часто более интересный вопрос, и он часто выявляет недостатки в дизайне того, что вы создаете.

Это не означает, что переключатели также никогда не следует использовать. Конечные автоматы, лексеры, синтаксические анализаторы и автоматы - все они в той или иной степени их используют, и, как правило, когда вы начинаете с симметричного ввода и переходите к асимметричному выводу, они могут быть полезны; вам просто нужно убедиться, что вы не используете переключатель как молоток, потому что вы видите в своем коде кучу гвоздей.

def f(x):
    dictionary = {'a':1, 'b':2, 'c':3}
    return dictionary.get(x,'Not Found') 
##Returns the value for the letter x;returns 'Not Found' if x isn't a key in the dictionary

Рассмотрите возможность включения краткого описания вашего кода и того, как он решает поставленный вопрос.

Henry Woody 28.09.2018 22:28

Хорошо, я сейчас добавил к этому комментарий.

Vikhyat Agarwal 30.10.2018 20:22

вы можете использовать отправленный dict:

#!/usr/bin/env python


def case1():
    print("This is case 1")

def case2():
    print("This is case 2")

def case3():
    print("This is case 3")


token_dict = {
    "case1" : case1,
    "case2" : case2,
    "case3" : case3,
}


def main():
    cases = ("case1", "case3", "case2", "case1")
    for case in cases:
        token_dict[case]()


if __name__ == '__main__':
    main()

Выход:

This is case 1
This is case 3
This is case 2
This is case 1

Я иногда использую это, но это не так ясно, как if / elif / elif / else

F.Tamy 12.01.2021 11:53

Другие вопросы по теме