[Python-Dev] Switch statement

M.-A. Lemburg mal at egenix.com
Tue Jun 20 10:57:37 CEST 2006


This discussion appears to repeat everything we already have
in the PEP 275:

http://www.python.org/dev/peps/pep-0275/

FWIW, below is a real-life use case that would
benefit from a switch statement or an optimization of the
existing if-elif-else case. It's the unpickler inner loop
of an XML pickle mechanism for Python objects.

Many parser doing the usual tokenize first, then parse the
tokens steps would benefit in the same way by avoiding the
function call overhead.

Note that you rarely have the situation where you need
to have a single cases for huge ranges of values (and
these can easily be handled in a separate if-else in the
else branch of the switch).

You do sometimes need to identical code for a few cases, so
allowing multiple values per case would make such use cases
have less code duplication.

However, using tuple syntax for
this would not be ideal, since a tuple may well be a valid value
to test for. This was discussed last time around: the only
way to cover this case is to always use tuple notation
for the values (see the syntax example in the PEP).

The code currently relies on Python interning
constants that appear in code, making the 'is' test slightly
faster than the '==' test.

        for tag in taglist:
            node = tag.name
            tagtype = tag.type

            if tagtype == DATA:
                if readdata:
                    data = tag.tag
                    readdata = 0
                continue

            # This is where the switch would start...

            elif node is 'int':

                if tagtype == STARTTAG:
                    readdata = 1
                    continue

                elif tagtype == ENDTAG:
                    stack.append(int(data))
                    continue

            elif node is 'float':

                if tagtype == STARTTAG:
                    readdata = 1
                    continue

                elif tagtype == ENDTAG:
                    stack.append(float(data))
                    continue

            elif node is 'long':

                if tagtype == STARTTAG:
                    readdata = 1
                    continue

                elif tagtype == ENDTAG:
                    stack.append(long(data))
                    continue

            elif node is 'string':

                if tagtype == STARTTAG:
                    refid = int(tag.attributes['id'])
                    readdata = 1
                    continue

                elif tagtype == ENDTAG:
                    data = xmlunescape(data, xmlentities)
                    obj =  data.encode('latin-1')
                    stack.append(obj)
                    memo[refid] = obj
                    continue

            elif node is 'tuple':

                if tagtype == STARTTAG:
                    refid = int(tag.attributes['id'])
                    pushframe((node, stack, refid))
                    stack = []
                    continue

                elif tagtype == ENDTAG:
                    obj = tuple(stack)
                    node, stack, refid = popframe()
                    memo[refid] = obj
                    stack.append(obj)
                    continue

            elif node is 'list':

                if tagtype == STARTTAG:
                    refid = int(tag.attributes['id'])
                    pushframe((node, stack, refid))
                    stack = []
                    continue

                elif tagtype == ENDTAG:
                    obj = list(stack)
                    node, stack, refid = popframe()
                    memo[refid] = obj
                    stack.append(obj)
                    continue

            elif node is 'dict':

                if tagtype == STARTTAG:
                    refid = int(tag.attributes['id'])
                    pushframe((node, stack, refid))
                    stack = []
                    continue

                elif tagtype == ENDTAG:
                    items = stack
                    node, stack, refid = popframe()
                    obj = {}
                    for k,v in items:
                        obj[k] = v
                    memo[refid] = obj
                    stack.append(obj)
                    continue

            elif node is 'item':

                if tagtype == STARTTAG:
                    continue

                elif tagtype == ENDTAG:
                    key = stack[-2]
                    value = stack[-1]
                    stack[-2] = (key, value)
                    del stack[-1]
                    continue

            elif node is 'key' or \
                 node is 'value':

                if tagtype == STARTTAG:
                    continue

                elif tagtype == ENDTAG:
                    continue

            elif node is 'none':

                if tagtype == STARTTAG:
                    stack.append(None)
                    continue

                elif tagtype == ENDTAG:
                    continue

            elif node is 'unicode':

                if tagtype == STARTTAG:
                    refid = int(tag.attributes['id'])
                    readdata = 1
                    continue

                elif tagtype == ENDTAG:
                    data = xmlunescape(data, xmlentities)
                    stack.append(obj)
                    memo[refid] = obj
                    continue

            elif node is 'ref':

                if tagtype == STARTTAG:
                    readdata = 1
                    continue

                elif tagtype == ENDTAG:
                    stack.append(memo[int(data)])
                    continue

            elif node is 'instance':

                if tagtype == STARTTAG:
                    attr = tag.attributes
                    refid = int(attr['id'])
                    classname = str(attr['class'])
                    #print 'instance:', repr(refid), repr(classname)
                    pushframe((node, stack, refid, classname))
                    stack = []
                    continue

                elif tagtype == ENDTAG:
                    initargs, state = stack
                    node, stack, refid, classname = popframe()
                    obj = self.create_instance(classname,
                                               initargs,
                                               state)
                    memo[refid] = obj
                    stack.append(obj)
                    continue

            elif node is 'initArgs':

                if tagtype == STARTTAG:
                    pushframe((node, stack))
                    stack = []
                    continue

                elif tagtype == ENDTAG:
                    obj = tuple(stack)
                    node, stack = popframe()
                    stack.append(obj)
                    continue

            elif node is 'dynamic':

                if tagtype == STARTTAG:
                    attr = tag.attributes
                    refid = int(attr['id'])
                    pushframe((node, stack, refid))
                    stack = []
                    continue

                elif tagtype == ENDTAG:
                    callable, args = stack[:2]
                    if len(stack) >= 3:
                        state = stack[2]
                    else:
                        state = None
                    node, stack, refid = popframe()
                    obj = self.create_object(callable, args, state)
                    memo[refid] = obj
                    stack.append(obj)
                    continue

            elif node is 'state' or \
                 node is 'callable' or \
                 node is 'args' or \
                 node is 'imag' or \
                 node is 'real':

                if tagtype in (STARTTAG, ENDTAG):
                    continue

            elif node is 'global':

                if tagtype == STARTTAG:
                    attr = tag.attributes
                    refid = int(attr['id'])
                    fullname = attr['name']
                    obj = self.find_global(fullname)
                    memo[refid] = obj
                    stack.append(obj)
                    continue

                elif tagtype == ENDTAG:
                    continue

            elif node is 'complex':

                if tagtype == STARTTAG:
                    continue

                elif tagtype == ENDTAG:
                    real, imag = stack[-2:]
                    stack[-2] = complex(imag, real)
                    del stack[-1]
                    continue

            elif node is 'xmlPickle':

                if tagtype == STARTTAG:
                    stack = []
                    continue

                elif tagtype == ENDTAG:
                    obj = stack[-1]
                    break

            # If we get here, something is wrong
            raise UnpicklingError, \
                  'unrecognized input data: tag %s' % tag.tag



-- 
Marc-Andre Lemburg
eGenix.com

Professional Python Services directly from the Source  (#1, Jun 20 2006)
>>> Python/Zope Consulting and Support ...        http://www.egenix.com/
>>> mxODBC.Zope.Database.Adapter ...             http://zope.egenix.com/
>>> mxODBC, mxDateTime, mxTextTools ...        http://python.egenix.com/
________________________________________________________________________
2006-07-03: EuroPython 2006, CERN, Switzerland              12 days left

::: Try mxODBC.Zope.DA for Windows,Linux,Solaris,FreeBSD for free ! ::::


More information about the Python-Dev mailing list