[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

AltStyle によって変換されたページ (->オリジナル) /