[Python-Dev] Simple Switch statement

Nick Coghlan ncoghlan at gmail.com
Sun Jun 25 03:56:20 CEST 2006


Raymond Hettinger wrote:
> [Phillip Eby]
>> I would like to be able to use switches on types, enumerations, and the like.
> 
> Be careful about wanting everything and getting nothing.
> My proposal is the simplest thing that gets the job done for key use cases found 
> in real code.
> Also, it is defined tightly enough to allow room for growth and elaboration over 
> time.
> Good luck proposing some alternative that is explainable, has no hidden 
> surprises,
> has an easy implementation, and allows fast hash-table style dispatch.

I like it!

You could actually make it even simpler by having the initial implementation 
only permit strings for the cases.

Then the concept is:
   1. Each case in the switch is given one or more string names
   2. The same name cannot appear more than once in a single switch statement
   3. A case is executed when the switch value matches one of its names
   4. The else clause is executed if the switch value does not match any case
   5. Case names use string-literal syntax to permit later expansion
   6. Switching on non-strings requires an auxiliary lookup

The advantage over the status quo is that instead of having to identify code 
directly (as in a function dispatch table), the auxiliary lookup only has to 
identify the name of the appropriate case.

And it still leaves the door open for all the other features being considered:
   - literals other than strings in the cases (integers, tuples)
   - arbitrary expressions in the cases (needs 'static' expressions first)
   - sequence unpacking using 'in' or '*'

> Besides, if you want to switch on other types, it is trivial to include a 
> reverse mapping
> (like that in the opcode.py example).  Reverse mappings are to build and easy to 
> read:

You can even build the jump table after the fact if everything you want to 
switch on is an existing global or builtin variable:

def switch_table(*args):
       # Build a string switch table for a set of arguments
       # All arguments must exist in the current global namespace
       # All arguments must be hashable
       all_items = globals().items()
       all_items.extend(__builtins__.__dict__.items())
       table = {}
       for obj in args:
           for name, value in all_items:
               if obj is value:
                   table[obj] = name
       return table

 >>> typemap = switch_table(float, complex, int, long, str, unicode, Decimal)
 >>> pprint(typemap)
{<class 'decimal.Decimal'>: 'Decimal',
  <type 'complex'>: 'complex',
  <type 'float'>: 'float',
  <type 'int'>: 'int',
  <type 'long'>: 'long',
  <type 'str'>: 'str',
  <type 'unicode'>: 'unicode'}

Armed with that switch table, you can then do:

   def fast_dispatch(self, other):
       switch typemap[other.__class__]
       case 'Decimal':
           self.handle_decimal(other)
       case 'int', 'long':
           self.handle_integer(other)
       case 'float':
           self.handle_float(other)
       case 'complex':
           self.handle_complex(other)
       case 'str', 'unicode':
           self.handle_string(other)
       else:
           self.handle_any(other)



-- 
Nick Coghlan   |   ncoghlan at gmail.com   |   Brisbane, Australia
---------------------------------------------------------------
             http://www.boredomandlaziness.org


More information about the Python-Dev mailing list