Michael
Michael

Reputation: 2556

How to emulate a switch-case in python using dictionaries

I am trying to emulate a switch-case statement from the validate_input2 function below.

def _validate_inputs2(*args):
    if len(args) == 1:
        stop = args
        start = 1
        step = 1
    elif len(args) == 2:
        start, stop = args
        step = 1
    elif len(args) == 3:
        start, stop, step = args
    else:
        raise TypeError("xxx expected at most 3 arguments, got 4")
    if 0 == step:
        raise ValueError("xxx arg 3 must not be zero")
    return start, stop, step

This is what I basically did but it doesn't work correctly

def _validate_inputs(*args):
    start, stop, step = {
        len(args) == 1: lambda x, y, z: (args, 1, 1),
        len(args) == 2: lambda x, y, z: (args, 1),
        len(args) == 3: args
    }.get(args, lambda: TypeError("xxx expected at most 3 arguments, got 4"))()
    if 0 == step:
        raise ValueError("xxx arg 3 must not be zero")
    return start, stop, step

Even though I find this emulation less readable I would like to better understand it in order to improve my python skills.

Can someone help me simplify this code?

Upvotes: 1

Views: 358

Answers (4)

Egidius
Egidius

Reputation: 1459

Good news for you, if you are still interested in using the switch case in Python. you can now use Match with Python 3.10

like this:

    match day:
        case 1:
            return "Sunday"
        case 2:
            return "Monday"
        case 3:
            return "Tuesday"
        case 4:
            return "Wednesday"
        case 5:
            return "Thursday"
        case 6:
            return "Friday"
        case 7:
            return "Saturday"

For more details read click here to read this python documentation

Upvotes: 0

pault
pault

Reputation: 43494

Here is a solution that builds upon what you have done:

def _validate_inputs(*args):
    if len(args) > 3:
        raise TypeError("xxx expected at most 3 arguments, got 4")
    else:
        start, stop, step = {
            1: (1,) + args + (1,),
            2: args + (1,),
            3: args
        }.get(len(args))
        if 0 == step:
            raise ValueError("xxx arg 3 must not be zero")
        return start, stop, step

Example outputs:

>>> print _validate_inputs(40)
(1, 40, 1)

>>> print(_validate_inputs(10, 20))
(10, 20, 1)

>>> print(_validate_inputs(1, 2, 3))
(1, 2, 3)

Edit: The TypeError wasn't working correctly in the original post. You can't return a TypeError as the not-found value in get() in this case, since the code is expecting 3 values to be unpacked (in python 2.x at least AFAIK).

I've updated the code to handle the case where len(args) > 3. One could also add a check for the case where args is None or empty.

>>> print(_validate_inputs(1, 2, 3, 4))
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-302-c2f9c1befae1> in <module>()
----> 1 print(_validate_inputs(1,2,3,4))

<ipython-input-296-769e989711e0> in _validate_inputs(*args)
      1 def _validate_inputs(*args):
      2     if len(args) > 3:
----> 3         raise TypeError("xxx expected at most 3 arguments, got 4")
      4     else:
      5         start, stop, step = {

TypeError: xxx expected at most 3 arguments, got 4

Upvotes: 3

Jake
Jake

Reputation: 637

I would try something like this..

def _validate_inputs(*args):
    start, stop, step = [0, 0, 0]
    dict = {1: [args, 1, 1], 2: args.append(1), 3: args}

    if len(args) in dict.keys():
         start, stop, step = dict[len(args)]
    else:
        raise TypeError("xxx expected at most 3 arguments, got "+str(len(args))))()

    if 0 == step:
        raise ValueError("xxx arg 3 must not be zero")
    return start, stop, step

Upvotes: 1

tobias_k
tobias_k

Reputation: 82889

(Not an answer to the question, but maybe a better approach to the actual problem.)

It seems like you are replicating part of what the Python slice builtin does. So you could just create a slice from the args and get the start, stop, and step from that.

>>> args = (2, 4)
>>> s = slice(*args)
>>> start, stop, step = s.start, s.stop, s.step
>>> start, stop, step
(2, 4, None)

This also takes care of handling the error cases:

>>> args = (1, 2, 3, 4)
>>> slice(*args)    
TypeError: slice expected at most 3 arguments, got 4

Upvotes: 2

Related Questions