Substituições para a declaração switch em Python?

quero escrever uma função em Python que devolve diferentes valores fixos com base no valor de um índice de entrada.

noutras línguas, eu usaria uma declaração switch ou case, mas o Python não parece ter uma declaração switch. Quais são as soluções Python recomendadas neste cenário?

Author: codeforester, 2008-09-13

30 answers

Podias usar um dicionário:

def f(x):
    return {
        'a': 1,
        'b': 2,
    }[x]
 1184
Author: Greg Hewgill, 2008-09-13 00:38:24

Se quiser predefinições, pode usar o dicionário get(key[, default]) Método:

def f(x):
    return {
        'a': 1,
        'b': 2
    }.get(x, 9)    # 9 is default if x not found
 1155
Author: Nick, 2017-07-06 22:51:30
Sempre gostei de o fazer assim.
result = {
  'a': lambda x: x * 5,
  'b': lambda x: x + 7,
  'c': lambda x: x - 2
}[value](x)

Daqui.

 312
Author: Mark Biek, 2014-02-16 05:06:42

Além dos métodos do dicionário (que eu realmente gosto, BTW), você também pode usar if-elif-else para obter a funcionalidade 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

Claro que isto não é idêntico ao switch/case - Você não pode ter queda-através tão facilmente como deixar de fora da declaração;, mas você pode ter um teste mais complicado. Sua formatação é melhor do que uma série de ifs aninhados, mesmo funcionalmente que é o que está mais perto.

 258
Author: Matthew Schinckel, 2015-06-10 14:07:33

A minha receita favorita em Python para switch/case é:

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

Curto e simples para cenários simples.

Comparar com 11 + linhas de código C:

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

Pode até atribuir várias variáveis usando tuplas:

choices = {'a': (1, 2, 3), 'b': (4, 5, 6)}
(result1, result2, result3) = choices.get(key, ('default1', 'default2', 'default3'))
 134
Author: ChaimG, 2015-08-16 21:58:26
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))

Utilização:

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

Testes:

n = 2
#Result:
#n is an even number.
#n is a prime number.
n = 11
#Result:
#Only single-digit numbers are allowed.
 87
Author: adamh, 2013-05-31 14:24:52
Há um padrão que aprendi com o código Python retorcido.
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'

Pode usá-lo sempre que precisar de enviar num token e executar um código alargado. Em uma máquina estatal você teria Métodos state_, e expedição em self.state. Este interruptor pode ser claramente estendido, herdando da classe base e definindo os seus próprios métodos do_. Muitas vezes você não terá métodos do_ na classe base.

editar: como exatamente é usado

Em caso de SMTP você receberá HELO do fio. O código relevante (de twisted/mail/smtp.py, modificado para o nosso caso) parece-se com este

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

Vais receber ' HELO foo.bar.com ' (ou podes receber 'QUIT' ou 'RCPT TO: foo'). Isto é tokenized em parts as ['HELO', 'foo.bar.com']. O nome verdadeiro da pesquisa do método é retirado de parts[0].

(o método original também é chamado state_COMMAND, porque usa o mesmo padrão para implementar uma máquina de Estado, i.e. getattr(self, 'state_' + self.mode))

 42
Author: , 2008-09-13 17:42:03
A minha favorita é uma receita muito boa. Vais mesmo gostar. É o mais próximo que vi de casos de mudança real, especialmente em características. Aqui está um exemplo:
# 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!"
 38
Author: John Doe, 2011-07-07 06:12:47
class Switch:
    def __init__(self, value): self._val = value
    def __enter__(self): return self
    def __exit__(self, type, value, traceback): return False # Allows traceback to occur
    def __call__(self, *mconds): return self._val in mconds

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
 30
Author: Ian Bell, 2017-12-15 20:25:07
Digamos que você não quer apenas devolver um valor, mas usar métodos que mudam algo em um objeto. Usando a abordagem indicada aqui seria:
result = {
  'a': obj.increment(x),
  'b': obj.decrement(x)
}.get(value, obj.default(x))

O que acontece aqui é que o python avalia todos os métodos no dicionário. Então, mesmo que o seu valor seja 'a', o objeto será aumentado e decrementado por X.

Solução:

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

result = func(*args)

Então você obtém uma lista contendo uma função e seus argumentos. Desta forma, apenas o ponteiro da função e o argumento a lista é devolvida, Não avaliada. o 'resultado' então avalia a chamada de função retornada.

 23
Author: GeeF, 2010-09-30 08:31:55
Vou deixar cair os meus dois cêntimos aqui. A razão pela qual não há uma declaração de caso/switch em Python é porque Python segue o princípio de 'só há uma maneira correta de fazer algo'. Então obviamente você poderia encontrar várias maneiras de recriar a funcionalidade de switch/case, mas a maneira Pythonic de realizar isso é a construção if / elif. ie
if something:
    return "first thing"
elif somethingelse:
    return "second thing"
elif yetanotherthing:
    return "third thing"
else:
    return "default thing"
Achei que o PEP 8 merecia um aceno aqui. Uma das coisas bonitas sobre Python é a sua simplicidade e elegância. Isso é em grande parte derivado dos princípios estabelecidos no PEP 8, incluindo"só há uma maneira certa de fazer algo"
 15
Author: user2233949, 2017-08-14 22:19:38
A expandir a ideia do dict como interruptor. se quiser usar um valor por omissão para a sua opção:
def f(x):
    try:
        return {
            'a': 1,
            'b': 2,
        }[x]
    except KeyError:
        return 'default'
 13
Author: Jeremy Cantrell, 2008-09-19 15:37:15

Se tem um bloco de casos complicado, pode considerar a utilização de uma tabela de pesquisa do dicionário de funções...

Se ainda não o fez antes é uma boa ideia entrar no seu depurador e ver exactamente como o dicionário procura cada função.

Nota: do not use "() " inside the case/dictionary lookup or it will call each of your functions as the dictionary / case block is created. Lembre-se disso porque você só quer chamar cada função uma vez usando um hash Procura estilo.

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()
 13
Author: htmlfarmer, 2012-10-17 21:52:45

Se está à procura de uma declaração extra, como" switch", construí um módulo python que estende o Python. É chamado ESPY como" estrutura melhorada para Python " e está disponível para ambos Python 2.x e Python 3.x.

Por exemplo, neste caso, uma declaração de comutação pode ser executada pelo seguinte código:

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

Que pode ser usado assim:

a=3
switch(a):
    case(0):
        print("Zero")
    case(1):
        print("Smaller than 2"):
        break
    else:
        print ("greater than 1")
Então espy traduz em Python como:
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
 13
Author: elp, 2018-08-28 15:09:16
Não encontrei a resposta simples que procurava no Google search. Mas descobri na mesma. É muito simples. Decidi postá-lo, e talvez evitar menos arranhões na cabeça de outra pessoa. A chave é simplesmente " em " e tuplas. Aqui está o comportamento da declaração switch com a queda, incluindo a queda aleatória.
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)

Prevê:

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.
 12
Author: JD Graham, 2013-10-12 18:43:57

Descobri que uma estrutura comum de comutação:

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

Pode ser expresso em Python do seguinte modo:

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

Ou formatado de uma forma mais clara:

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

Em vez de ser uma declaração, a versão em python é uma expressão, que avalia para um valor.

 12
Author: leo, 2015-05-29 17:25:57

As soluções que uso:

Uma combinação de 2 das soluções postadas aqui, que é relativamente fácil de ler e suporta defaults.

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

Onde

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

Olha para cima "lambda x: x - 2" no dict e usa-o com x=23

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

Não o encontra no dict e usa o padrão "lambda x: x - 22" com x=44.

 10
Author: thomasf1, 2012-02-23 16:27:48
# 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
 8
Author: user5224656, 2015-10-24 01:17:46
Fiz uma solução (relativamente) flexível e reutilizável para isto. Pode ser encontrado em GitHub como este gist . Se o resultado da função switch é callable, é chamado automaticamente.
 6
Author: , 2009-06-05 14:20:52
Gostei da resposta do Mark Bies.

Uma vez que a variável x deve ser usada duas vezes, modifiquei as funções lambda para sem parâmetros.

Eu tenho que correr com 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'

Edit: reparei que posso usar None o tipo com dicionários. Para que isto emulasse switch ; case else

 6
Author: guneysus, 2017-05-23 11:47:36
A maioria das respostas aqui são bastante antigas, e especialmente as aceites, por isso parece que vale a pena actualizar.

Primeiro, a FAQ oficial em Python cobre isto, e recomenda a cadeia elif para casos simples e a dict para casos maiores ou mais complexos. Também sugere um conjunto de métodos visit_ (um estilo usado por muitos frameworks de servidores) para alguns casos:

def dispatch(self, value):
    method_name = 'visit_' + str(value)
    method = getattr(self, method_name)
    method()
A FAQ também menciona o PEP 275, que foi escrito para obter um oficial de uma vez por todas. decisão sobre a adição de C-style switch declarações. Mas esse PEP foi realmente adiado para o Python 3, e foi apenas oficialmente rejeitado como uma proposta separada, PEP 3103. A resposta foi, naturalmente, não-mas os dois PEPs têm links para informações adicionais se você estiver interessado nas razões ou na história.
Uma coisa que surgiu várias vezes (e pode ser vista em PEP 275, apesar de ter sido cortada como uma recomendação real) é que se você está realmente incomodado por ter 8 linhas de código para lidar com 4 casos, vs. as 6 linhas que você teria em C ou Bash, você pode sempre escrever isto:
if x == 1: print('first')
elif x == 2: print('second')
elif x == 3: print('third')
else: print('did not place')
Isto não é propriamente encorajado pelo PEP 8, mas é legível e não muito indiomático.
Ao longo de mais de uma década desde que a PEP 3103 foi rejeitada, a questão das declarações de casos em estilo C, ou mesmo a versão um pouco mais poderosa em Go, tem sido considerada morta; sempre que alguém o traz para cima em python-ideas ou-dev, eles são referidos ao velho decisao. No entanto, a ideia de uma correspondência completa dos padrões do tipo ML surge de poucos em poucos anos, especialmente porque línguas como a Swift e a Rust a adoptaram. O problema é que é difícil obter muito uso fora da correspondência de padrões sem tipos de dados algébricos. Embora o Guido tenha sido compreensivo com a ideia, ninguém apresentou uma proposta que se encaixe muito bem no Python. (Você pode ler meu strawman 2014 por exemplo.) Esta situação poderia mudar com {[5] } em 3.7 e algumas propostas esporádicas para um enum mais poderoso para lidar com tipos de soma, ou com várias propostas para diferentes tipos de declarações-encadernações locais (como PEP 3150 , ou o conjunto de propostas atualmente em discussão on-ideas). Mas até agora, não aconteceu. Há também, ocasionalmente, propostas para a correspondência Perl 6, o que é basicamente uma mistura de tudo, desde {[[2]} até à troca de tipo de expedição única.
 6
Author: abarnert, 2018-04-10 06:13:39
def f(x):
     return 1 if x == 'a' else\
            2 if x in 'bcd' else\
            0 #default

Curto e fácil de ler, tem um valor padrão e suporta expressões em ambas as condições e valores de retorno.

No entanto, é menos eficiente do que a solução com um dicionário. Por exemplo, Python tem que analisar todas as condições antes de retornar o valor padrão.
 5
Author: emu, 2012-11-05 20:05:12

Acho que a melhor maneira é usar a linguagem python para manter o seu código testável. Como mostrado em respostas anteriores, eu uso dicionários para tirar vantagem das estruturas e linguagem python e manter o código de" caso " isolado em diferentes métodos. Abaixo está uma classe, mas você pode usar diretamente um módulo, globals e funções. A classe tem métodos que podem ser testados com isolamento . Dependendo das suas necessidades, você pode jogar com métodos estáticos e atributos também.

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)

É possível tirar partido deste método usando também as classes como chaves de "__escolha_Tabela". Desta forma você pode evitar é abuso de substâncias e manter tudo limpo e testável.

Suponha que você tem que processar um monte de mensagens ou pacotes a partir da rede ou do seu MQ. Cada pacote tem sua própria estrutura e seu código de gestão (de uma forma genérica). Com o código acima é possível fazer algo assim:

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)
Então ... a complexidade não é espalhada no fluxo de código, mas é renderizada na estrutura de código.
 4
Author: J_Zar, 2016-04-20 14:54:43

Fiz esta pequena e limpa solução

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

Onde o foo1 (), o foo2 (), o foo3 () e o default () são funções

 4
Author: Alejandro Quintanar, 2018-04-17 05:10:40

Definição:

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

Permite-lhe usar uma sintaxe bastante simples, com os casos agrupados num mapa:

def sample1(x):
  local = 'betty'
  switch1(x, {
    'a': lambda: print("hello"),
    'b': lambda: (
      print("goodbye," + local),
      print("!")),
    })
Continuei a tentar redefinir o interruptor de uma forma que me permitisse livrar-me do "lambda", mas desisti. Alterando a definição:
def switch(value, *maps):
  options = {}
  for m in maps:
    options.update(m)
  if value in options:
    options[value]()
  elif None in options:
    options[None]()

Permitiu-me mapear vários casos para o mesmo código, e fornecer uma opção predefinida:

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")
    })

Cada caso replicado tem de estar no seu próprio dicionário; switch () consolida os dicionários antes de procurar valor. Ainda é mais feio do que eu gostaria, mas tem a eficiência básica de usar um olhar hashed na expressão, em vez de um loop através de todas as chaves.

 3
Author: William H. Hooper, 2013-07-25 18:23:33
Fiquei bastante confuso depois de ler a resposta, mas isto esclareceu tudo.
def numbers_to_strings(argument):
    switcher = {
        0: "zero",
        1: "one",
        2: "two",
    }
    return switcher.get(argument, "nothing")

Este código é análogo a:

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

Verifique a fonte Para mais informações sobre o mapeamento de dicionário para funções.

 3
Author: Yster, 2017-06-19 11:49:28

Uma solução que tenho tendência a usar e que também faz uso de dicionários é:

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)()
Isto tem a vantagem de não tentar avaliar as funções todas as vezes, e você só tem que garantir que a função externa recebe toda a informação que as funções internas precisam.
 3
Author: Tony Suffolk 66, 2018-06-06 16:45:58

Inspirado poresta resposta impressionante . Não requer código externo. Não foi testado. Cair não funciona bem.

for case in [expression]:
    if case == 1:
        do_stuff()
        # Fall through

    # Doesn't fall through INTO the later cases
    if case in range(2, 5):
        do_other_stuff()
        break

    do_default()
 3
Author: Solomon Ucko, 2018-09-26 21:44:57

Se não se preocupar em perder o realce de sintaxe dentro das suites do caso, pode fazer o seguinte:

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

Onde value é o valor. Em C, isto seria:

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

Também podemos criar uma função auxiliar para fazer isto:

def switch(value, cases, default):
    exec cases.get(value, default)
Então podemos usá - lo assim, por exemplo, com um, dois e três:
switch(value, {
    1: """
print ('one')
    """, 
    2: """
print ('two')
    """, 
    3: """
print ('three')
    """,
}, """
print ('None')
""")
 2
Author: DCPY, 2016-05-25 22:56:30
Expandindo a resposta de Greg Hewgill podemos encapsular a solução do dicionário usando um decorador.
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

Isto pode então ser usado com o @case-decorador

@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
A boa notícia é que isto já foi feito no módulo NeoPySwitch. Instalar simplesmente com o pip:
pip install NeoPySwitch
 2
Author: Tom, 2017-05-23 12:26:42