switch-statement case español - ¿Reemplazos para la instrucción switch en Python?





15 Answers

Si desea valores predeterminados, puede usar el método de get(key[, default]) diccionario get(key[, default]) :

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

Quiero escribir una función en Python que devuelva diferentes valores fijos según el valor de un índice de entrada.

En otros idiomas, usaría una declaración de switch o case , pero Python no parece tener una declaración de switch . ¿Cuáles son las soluciones Python recomendadas en este escenario?




Además de los métodos de diccionario (que realmente me gustan, por cierto), también puede usar if-elif-else para obtener la funcionalidad de cambio / caso / predeterminado:

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

Por supuesto, esto no es idéntico al interruptor / caja: no puede tener caídas tan fácilmente como dejar de lado la ruptura; declaración, pero puede tener una prueba más complicada. Su formato es mejor que una serie de ifs anidados, aunque funcionalmente eso es lo que está más cerca.




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

Pruebas:

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



Mi favorita es una muy buena recipe . Realmente te gustará. Es el más cercano que he visto a las declaraciones de casos de cambio reales, especialmente en características.

Aquí hay un ejemplo:

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



Digamos que no solo desea devolver un valor, sino que desea utilizar métodos que cambian algo en un objeto. Usando el enfoque indicado aquí sería:

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

Lo que sucede aquí es que Python evalúa todos los métodos en el diccionario. Entonces, incluso si su valor es 'a', el objeto se incrementará y disminuirá en x.

Solución:

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

result = func(*args)

Así que obtienes una lista que contiene una función y sus argumentos. De esta manera, solo el puntero a la función y la lista de argumentos se devuelven, no se evalúan. 'resultado' luego evalúa la función devuelta llamada.




ampliando la idea de "dict como interruptor". Si desea utilizar un valor predeterminado para su conmutador:

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



Si estás buscando una declaración extra, como "switch", construí un módulo de Python que extiende Python. Se llama ESPY como "Estructura mejorada para Python" y está disponible para Python 2.xy Python 3.x.

Por ejemplo, en este caso, una instrucción de cambio podría realizarse mediante el siguiente 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 se puede utilizar de esta manera:

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

Así que traduce en 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



Encontré que una estructura de interruptor común:

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

Se puede expresar en Python de la siguiente manera:

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

o formateado de una manera más clara:

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

En lugar de ser una declaración, la versión de python es una expresión, que se evalúa como un valor.




# 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



Me gustó la respuesta de Mark Bies.

Como la variable x debe usar dos veces, modifiqué las funciones lambda a sin parámetros.

Tengo que correr con 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'

Edición: Noté que puedo usar el tipo None con los diccionarios. Así que esto emularía el switch ; case else switch ; case else




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

Corto y fácil de leer, tiene un valor predeterminado y admite expresiones en ambas condiciones y valores de retorno.

Sin embargo, es menos eficiente que la solución con un diccionario. Por ejemplo, Python tiene que escanear todas las condiciones antes de devolver el valor predeterminado.




Hice esta solución pequeña y limpia.

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

donde foo1 (), foo2 (), foo3 () y default () son funciones




Estaba bastante confundido después de leer la respuesta, pero esto lo aclaró todo:

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

Este código es análogo a:

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

Compruebe la Source para obtener más información sobre la asignación de diccionario a las funciones.




Inspirado por esta asombrosa respuesta . No requiere código externo. No probado. Caerse a través no funciona correctamente.

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



Ampliando la respuesta de Greg Hewgill : podemos encapsular la solución del diccionario utilizando un 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

Esto puede ser usado con el @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

La buena noticia es que esto ya se ha hecho en el módulo NeoPySwitch . Simplemente instale usando pip:

pip install NeoPySwitch





Related