Switch statement

Steven D'Aprano steve+comp.lang.python at pearwood.info
Sun Mar 10 16:18:08 CET 2013


On Sun, 10 Mar 2013 14:16:27 +0000, Joseph L. Casale wrote:

> I have a switch statement composed using a dict:
> 
> 
> switch = {
>     'a': func_a,
>     'b': func_b,
>     'c': func_c
> }
> switch.get(var, default)()
> 
> 
> As a result of multiple functions per choice, it migrated to:
> 
> 
> 
> switch = {
>     'a': (func_a1, func_a2),
>     'b': (func_b1, func_b2),
>     'c': (func_c, )
> }
> 
> 
> 
> for f in switch.get(var, (default, )):
>     f()
> 
> 
> As a result of only some of the functions now requiring unique
> arguments, I presume this needs to be migrated to a if/else statement?
> Is there a way to maintain the switch style with the ability in this
> scenario to cleanly pass args only to some functions?


The dict-as-switch-statement pattern only works when the functions all 
take the same argument(s). Otherwise, you need to check which function 
you are calling, and provide the right arguments.

So either use the if...elif...else pattern, or you need to modify those 
functions to take the same arguments. For example, suppose I have three 
functions taking different arguments:

spam(a)
ham(b)
eggs(c)

Instead of storing spam, ham and eggs in my switch-dict, I store three 
wrapper functions:

switch = {
    'A': lambda a, b, c: spam(a), 
    'B': lambda a, b, c: ham(b), 
    'C': lambda a, b, c: eggs(c),
    }

and then unconditionally call the function with all three arguments:

switch[letter](a, b, c)

The wrappers take care of ignoring the arguments that should be ignored, 
and calling the correct function with the right argument.


Here's another similar case. Suppose the functions are called like this:

spam(a, b)
ham(b, c)
eggs(b)

and furthermore, the arguments a and c are known ahead of time, with only 
b varying. I can make one-argument versions of the spam and ham functions 
using either the functools module or a lambda with a default value:

switch = {
    'A': functools.partial(spam, a),
    'B': lambda b, c=c: ham(b, c), 
    'C': eggs,
    }

switch[letter](b)

I stress that this version only applies if the extra arguments are known 
ahead of time. If they aren't known until you look-up the switch, you 
can't use this tactic.

functools.partial isn't always applicable, but when it is, you should 
prefer it over lambda since it will be very slightly more efficient.



-- 
Steven



More information about the Python-list mailing list