[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