w3schools - usar o if python




Substituições para a instrução switch em Python? (20)

A maioria das respostas aqui são bem antigas, e especialmente as aceitas, então parece valer a pena atualizar.

Primeiro, o FAQ oficial do Python cobre isso e recomenda a cadeia elif para casos simples e o dict para casos maiores ou mais complexos. Também sugere um conjunto de métodos visit_ (um estilo usado por muitas estruturas de servidor) para alguns casos:

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

O FAQ também menciona o PEP 275 , que foi escrito para obter uma decisão oficial definitiva sobre a adição de declarações de switch no estilo C. Mas esse PEP foi de fato adiado para o Python 3 e só foi oficialmente rejeitado como uma proposta separada, o PEP 3103 . A resposta foi, obviamente, não - mas os dois PEPs têm links para informações adicionais se você estiver interessado nas razões ou no histórico.

Uma coisa que surgiu várias vezes (e pode ser vista no PEP 275, mesmo que tenha sido recortada como uma recomendação real) é que, se você está realmente incomodado com 8 linhas de código para lidar com 4 casos, contra os 6 linhas que você tem em C ou Bash, você sempre pode escrever isto:

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

Isso não é exatamente incentivado pelo PEP 8, mas é legível e não muito unidiomático.

Ao longo de mais de uma década desde que o PEP 3103 foi rejeitado, a questão das declarações de caso do estilo C, ou mesmo a versão um pouco mais poderosa em Go, foi considerada morta; sempre que alguém menciona python-ideas ou -dev, eles são encaminhados para a velha decisão.

No entanto, a ideia de uma correspondência completa de padrões no estilo ML surge a cada poucos anos, especialmente desde que linguagens como Swift e Rust a adotaram. O problema é que é difícil obter muito uso de correspondência de padrões sem tipos de dados algébricos. Enquanto Guido tem sido simpático à ideia, ninguém apresenta uma proposta que se encaixe muito bem no Python.(Você pode ler meu palhinho de 2014 para um exemplo.) Isso pode mudar com a dataclassversão 3.7 e algumas propostas esporádicas para um mais poderoso enumlidar com tipos de soma, ou com várias propostas para diferentes tipos de enlaces de instruções locais (como o PEP 3150 ou o conjunto de propostas atualmente em discussão sobre as idéias). Mas até agora, não tem.

Há também ocasionalmente propostas para correspondência no estilo Perl 6, que é basicamente uma miscelânea de tudo, desde elifregex até troca de tipo single-dispatch.

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

Em outras linguagens eu usaria um switch ou uma instrução case , mas o Python não parece ter uma instrução switch . Quais são as soluções Python recomendadas neste cenário?


Além dos métodos de 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

Isto, obviamente, não é idêntico ao switch / case - você não pode ter fall-through tão facilmente quanto deixar o break; declaração, mas você pode ter um teste mais complicado. Sua formatação é melhor do que uma série de ifs aninhados, embora funcionalmente é o que está mais próximo.


Digamos que você não queira apenas retornar um valor, mas deseja usar métodos que alterem 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. Portanto, mesmo que seu valor seja 'a', o objeto será incrementado 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 de função e a lista de argumentos são retornados, não avaliados. 'result', em seguida, avalia a chamada de função retornada.


Eu achei que uma estrutura de switch comum:

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

pode ser expresso em Python da seguinte maneira:

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

ou formatado de maneira 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 do python é uma expressão avaliada como um valor.


Eu gostei da resposta de Mark Bies

Como 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: notei que eu posso usar None tipo com com dicionários. Então, isso seria emular o switch ; case else switch ; case else


Eu só vou deixar meus dois centavos aqui. A razão pela qual não há uma instrução case / switch no Python é porque o Python segue o princípio de "Há apenas um jeito certo de fazer alguma coisa". Então, obviamente, você poderia criar várias maneiras de recriar a funcionalidade switch / case, mas a maneira Python de realizar isso é a construção if / elif. ou seja

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

Eu apenas senti PEP 8 mereceu um aceno de cabeça aqui. Uma das coisas bonitas sobre o Python é sua simplicidade e elegância. Isso é em grande parte derivado dos princípios estabelecidos no PPE 8, incluindo "Há apenas um jeito certo de fazer algo"


Há um padrão que aprendi com o código 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'

Você pode usá-lo sempre que precisar despachar um token e executar uma parte extensa do código. Em uma máquina de estados, você teria métodos state_ e despacharia em self.state . Essa opção pode ser estendida de forma limpa herdando da classe base e definindo seus próprios métodos. Muitas vezes você não terá do_ métodos na classe base.

Edit: exatamente como isso é usado

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

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

Você receberá ' HELO foo.bar.com ' (ou poderá receber 'QUIT' ou 'RCPT TO: foo' ). Isso é tokenizado em parts como ['HELO', 'foo.bar.com'] . O nome da pesquisa do método atual é obtido das parts[0] .

(O método original também é chamado de state_COMMAND , porque ele usa o mesmo padrão para implementar uma máquina de estado, ou seja, getattr(self, 'state_' + self.mode) )


Meu favorito é uma recipe muito legal. Você realmente vai gostar. É o mais próximo que já vi para as declarações reais de switch, especialmente em recursos.

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!"

Não encontrei a resposta simples que procurava em qualquer parte da pesquisa do Google. Mas eu percebi isso de qualquer maneira. É muito simples. Decidiu postar e talvez evitar alguns arranhões na cabeça de outra pessoa. A chave é simplesmente "in" e tuplas. Aqui está o comportamento da instrução switch com fall-through, incluindo fall-through RANDOM.

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)

Fornece:

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.

Se você está pesquisando extra-statement, como "switch", eu construí um módulo python que estende o Python. É chamado de ESPY como "Enhanced Structure for Python" e está disponível para o Python 2.xe o Python 3.x.

Por exemplo, nesse caso, uma instrução switch poderia 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 traduzi-lo 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

Se você tem um bloco de casos complicado, pode considerar a utilização de uma tabela de consulta de dicionário de função ...

Se você não fez isso antes, é uma boa idéia entrar no seu depurador e ver exatamente como o dicionário pesquisa cada função.

NOTA: Não use "()" dentro da busca de caso / dicionário ou ele chamará cada uma de suas funções quando o dicionário / bloco de casos for criado. Lembre-se disso porque você só deseja chamar cada função uma vez usando uma pesquisa de estilo de hash.

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()

Você poderia usar um dicionário:

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

Definindo:

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

permite que você use uma sintaxe razoavelmente direta, com os casos agrupados em um mapa:

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

Eu continuei tentando redefinir o switch de uma maneira que me deixasse livrar do "lambda", mas desisti. Ajustando 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 padrão:

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 deve estar em seu próprio dicionário; switch () consolida os dicionários antes de procurar o valor. Ainda é mais feio do que eu gostaria, mas tem a eficiência básica de usar uma pesquisa com hash na expressão, em vez de um loop através de todas as teclas.


Eu fiz essa solução pequena e limpa

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

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


Se você não se preocupar em perder o destaque de sintaxe dentro dos conjuntos de casos, poderá fazer o seguinte:

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

Onde valueestá o valor. Em C, isso 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 isso:

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

Então podemos usá-lo assim para o exemplo com um, dois e três:

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

Uma solução que costumo 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)()

Isso tem a vantagem de não tentar avaliar as funções todas as vezes, e você só precisa garantir que a função externa receba todas as informações de que as funções internas precisam.


Expandindo a resposta de Greg Hewgill - Podemos encapsular a solução de 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

Isso pode ser usado com o @casedecodificador

@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 isso já foi feito no NeoPySwitch NeoPySwitch. Basta instalar usando pip:

pip install NeoPySwitch

Inspirado por esta resposta incrível . Não requer código externo. Não testado. Queda não funciona corretamente.

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()

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

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

Uso:

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.




switch-statement