OT: Re: Just took a look in the perl newsgroup....

Bengt Richter bokr at oz.net
Thu May 29 12:34:57 EDT 2003


On Wed, 28 May 2003 23:10:57 -0600, Steven Taschuk <staschuk at telusplanet.net> wrote:

>Quoth Bengt Richter:
>> On Wed, 28 May 2003 14:17:37 -0600, Steven Taschuk <staschuk at telusplanet.net> wrote:
>> >Quoth Bengt Richter:
>  [...]
>> >>         ## a local case structure with rebinding in local scope
>> >>         try: raise `x`
>> >>         except '1':
>  [...]
>> >Inherently fragile due to reliance on interning of repr(x).  Won't
>> >work at all if/when string exceptions go away.
>>
>> Which version requires interning of repr(x)? It looks like the code is less
>> efficient than the corresponding if/elif/else code, however.
>
>It is the quoted try/except version that relies on interning.  For
>example:
>
>    >>> x = 12345
>    >>> try:
>    ...     raise `x`
>    ... except '12345':
>    ...     print 'case 12345'
>    ... 
>    Traceback (most recent call last):
>      File "<stdin>", line 2, in ?
>    12345
>
>Because string exceptions are caught by identity, not equality,
>and, as it happens, '12345' doesn't get interned.
ITYM `12345` doesn't get "interned" (neither does '1234'+'5')

>
>  [...]
>> class Switch(object):
>>     def __init__(self, *caseNames):
>>         for name in caseNames:
>>             if not isinstance(name,str): name = `name`
>>             exec ('class _%s(Exception):pass'%name) in self.__dict__
>>             del self.__dict__['__builtins__']
>>     def __call__(self, name):
>>         raise getattr(self, '_%s'%name, ValueError)
>
>Yikes again.  This one depends on repr(x) fitting into identifier
>syntax, so I couldn't use it with tuples (to pick one example of
>many).

Sheesh ;-)

====< caseswitch.py >=============================================
class Switch(object):
    def __init__(self, *caseNames):
        self.halias = {}
        for name in caseNames:
            try:
                hname = '_%X' % hash(name)
            except TypeError:
                raise ValueError, 'Switch requires hashable case values'
            exec ('class %s(Exception):pass'%hname) in self.__dict__
            self.halias[name] = getattr(self, hname)
        del self.__dict__['__builtins__']
    def __call__(self, name):
        raise self.halias.get(name, ValueError)
    def __getitem__(self, iargs):
        if not isinstance(iargs, tuple): iargs = (iargs,)
        return tuple([self.halias.get(i, '') for i in iargs])
==================================================================
====< zcase.py >==================================================
from caseswitch import Switch
CASES = (1, 2, 'foo', ('a', 'tuple'), 4, 5)
case = switch = Switch(*CASES)

def f(x):
    def g(x):
        inner_var = 5      
        ## a local case structure with rebinding in local scope
        try: switch(x)
        except case[1]:
            # case code in same scope as case
            inner_var = '<<value bound in scope of "case" 1)>>'
        except case[2]:
            inner_var = '<<value bound in scope of "case" 2>>'
        except case['foo', 4 ,5]:
            inner_var = '<<value bound in scope of "case" foo, 4, 5>>'
        except case[('a', 'tuple'),]:
            inner_var = '''<<value bound in scope of "case" ('a', 'tuple')>>'''
        except:
            inner_var = '<<value bound in scope of "case" default>>'
        print 'inner_var as seen at end of "case":', inner_var
    g(x)

for i in CASES + (0,): print '---- f(%r) -----'%(i,); f(i)
==================================================================
[ 9:31] C:\pywk\clp>zcase.py
---- f(1) -----
inner_var as seen at end of "case": <<value bound in scope of "case" 1)>>
---- f(2) -----
inner_var as seen at end of "case": <<value bound in scope of "case" 2>>
---- f('foo') -----
inner_var as seen at end of "case": <<value bound in scope of "case" foo, 4, 5>>
---- f(('a', 'tuple')) -----
inner_var as seen at end of "case": <<value bound in scope of "case" ('a', 'tuple')>>
---- f(4) -----
inner_var as seen at end of "case": <<value bound in scope of "case" foo, 4, 5>>
---- f(5) -----
inner_var as seen at end of "case": <<value bound in scope of "case" foo, 4, 5>>
---- f(0) -----
inner_var as seen at end of "case": <<value bound in scope of "case" default>>


Note that I had to make a choice re the tuple ambiguity. I.e., case[('a', 'tuple'),]
would be the same as case['a', 'tuple'] if you leave out the comma, which would specify
two cases instead of a single tuple case.

Of course this is not terribly efficient code compared to the corresponding if/elif/else chain ;-)
I'm not recommending anyone adopt use of caseswitch.py, but IMO it reads fairly well
and does a lot of what you'd like a real case mechanism for python to do ;-)

Regards,
Bengt Richter




More information about the Python-list mailing list