Switch statement

J

Joseph L. Casale

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 theswitch style with
the ability in this scenario to cleanly pass args only to some functions?


Thanks,
jlc
 
S

Steven D'Aprano

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.
 
J

Joseph L. Casale

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

That's cool, never even thought to use lambdas.
functools.partial isn't always applicable, but when it is, you should
 prefer it over lambda since it will be very slightly more efficient.


Ok, haven't used this before but I will give it a read!


Much appreciated Steven!
jlc
 
T

Terry Reedy

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.

If, for instance, the functions take either 0 or 1 arg and the 1 arg is
always the same, an alternative to the other suggestions is to look at
the signature in an if statement. In 3.3 this is relatively ease, as
inspect.signature(func) returns a signature object. There are more
complicated paths in earlier versions.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,996
Messages
2,570,238
Members
46,826
Latest member
robinsontor

Latest Threads

Top