Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.python > #41016 > unrolled thread

Switch statement

Started by"Joseph L. Casale" <jcasale@activenetwerx.com>
First post2013-03-10 14:16 +0000
Last post2013-03-10 18:02 -0400
Articles 4 — 3 participants

Back to article view | Back to comp.lang.python


Contents

  Switch statement "Joseph L. Casale" <jcasale@activenetwerx.com> - 2013-03-10 14:16 +0000
    Re: Switch statement Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2013-03-10 15:18 +0000
      RE: Switch statement "Joseph L. Casale" <jcasale@activenetwerx.com> - 2013-03-10 17:51 +0000
      Re: Switch statement Terry Reedy <tjreedy@udel.edu> - 2013-03-10 18:02 -0400

#41016 — Switch statement

From"Joseph L. Casale" <jcasale@activenetwerx.com>
Date2013-03-10 14:16 +0000
SubjectSwitch statement
Message-ID<mailman.3155.1362925062.2939.python-list@python.org>
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?


Thanks,
jlc

[toc] | [next] | [standalone]


#41018

FromSteven D'Aprano <steve+comp.lang.python@pearwood.info>
Date2013-03-10 15:18 +0000
Message-ID<513ca430$0$6512$c3e8da3$5496439d@news.astraweb.com>
In reply to#41016
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

[toc] | [prev] | [next] | [standalone]


#41023

From"Joseph L. Casale" <jcasale@activenetwerx.com>
Date2013-03-10 17:51 +0000
Message-ID<mailman.3157.1362937989.2939.python-list@python.org>
In reply to#41018
> 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

[toc] | [prev] | [next] | [standalone]


#41041

FromTerry Reedy <tjreedy@udel.edu>
Date2013-03-10 18:02 -0400
Message-ID<mailman.3170.1362952971.2939.python-list@python.org>
In reply to#41018
On 3/10/2013 11:18 AM, Steven D'Aprano wrote:
> 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.

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.

-- 
Terry Jan Reedy

[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.python


csiph-web