Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Just took a look in the perl newsgroup....

0 views
Skip to first unread message

Graham Nicholls

unread,
May 19, 2003, 11:24:51 AM5/19/03
to
And remembered why I decided I must learn Python :-)
I clearly need to learn "the Python Way", which _is_ quite different, and
has its good and bad points (stamps foot. I _want_ a case statement).
But thank goodness for the sparse syntax, and minimalism. I guess I'll live
with no case just to forget about @ % $ etc.
Graham
--
Graham Nicholls
All round good guy.

Aahz

unread,
May 19, 2003, 12:21:24 PM5/19/03
to
In article <1H6ya.6977$573....@news-binary.blueyonder.co.uk>,

Graham Nicholls <gra...@rockcons.co.uk> wrote:
>
>And remembered why I decided I must learn Python :-)

Congrats! Hallelujah! You've seen the light! ;-)

>I clearly need to learn "the Python Way", which _is_ quite different,
>and has its good and bad points (stamps foot. I _want_ a case
>statement). But thank goodness for the sparse syntax, and minimalism.
>I guess I'll live with no case just to forget about @ % $ etc.

Don't forget that in many situations Python's substitutes for
switch/case are better than an actual switch/case. Even more don't
forget that Perl doesn't actually have a switch/case, either.
--
Aahz (aa...@pythoncraft.com) <*> http://www.pythoncraft.com/

"In many ways, it's a dull language, borrowing solid old concepts from
many other languages & styles: boring syntax, unsurprising semantics,
few automatic coercions, etc etc. But that's one of the things I like
about it." --Tim Peters on Python, 16 Sep 93

Graham Nicholls

unread,
May 19, 2003, 3:54:16 PM5/19/03
to
Aahz wrote:

> In article <1H6ya.6977$573....@news-binary.blueyonder.co.uk>,
> Graham Nicholls <gra...@rockcons.co.uk> wrote:
>>
>>And remembered why I decided I must learn Python :-)
>
> Congrats! Hallelujah! You've seen the light! ;-)
>
>>I clearly need to learn "the Python Way", which _is_ quite different,
>>and has its good and bad points (stamps foot. I _want_ a case
>>statement). But thank goodness for the sparse syntax, and minimalism.
>>I guess I'll live with no case just to forget about @ % $ etc.
>
> Don't forget that in many situations Python's substitutes for
> switch/case are better than an actual switch/case. Even more don't
> forget that Perl doesn't actually have a switch/case, either.

I believe its to be part of perl6, but don't know when thats due. Perl6 also
tidies up variable oh whats the name of them , you know the $% etc.

Gerrit Holl

unread,
May 19, 2003, 3:11:32 PM5/19/03
to
Graham Nicholls schreef op maandag 19 mei om 17:28:03 +0000:
> Subject: Just took a look in the perl newsgroup....

Does it have a bad atmosphere?

> And remembered why I decided I must learn Python :-)

I have never read the Perl newsgroup. I have, however, once encountered
a thread with a very bad atmosphere in c.l.py, and then found out that
it was crossposted in c.l.pl...

I have heard c.l.ruby has a great atmosphere, too.

My first ng-experience was nl.comp.programmeren, which has a very
bad atmosphere...

> I clearly need to learn "the Python Way", which _is_ quite different,

Apparantly, it is. That may be the reason for me that it'll get
very difficult to learn ever another language...

> and
> has its good and bad points (stamps foot. I _want_ a case statement).

Similarly, some want a ternary operator. I don't know whether you were
here yet with the PEP-308 discussion, but this lead to countless
changing .procmailrc's. There is no decision taken yet.

The ternary-discussion keeps coming back. The same is true for case, to
a lesser extent. Maybe a PEP-333 should for once and for ever end this
discussion, too.

> But thank goodness for the sparse syntax, and minimalism. I guess I'll live
> with no case

> just to forget about @ % $ etc.

Heh heh. I have been looking at Ruby code and thought it contained a lot of
@, % and $. Now a a random line from a random .pl:

$math_start_rx = "(\\\$|\\\\\\(|\\\\math\\b)(\\begin(($O|$OP)\\d+($C|$CP))tex2html_wrap\\4)?";

Am *I* happy about raw strings!

yours,
Gerrit.

--
63. If he transform waste land into arable fields and return it to its
owner, the latter shall pay him for one year ten gur for ten gan.
-- Hammurabi, Code of Law
--
Asperger Syndroom - een persoonlijke benadering:
http://people.nl.linux.org/~gerrit/
Het zijn tijden om je zelf met politiek te bemoeien:
http://www.sp.nl/

Michael Chermside

unread,
May 19, 2003, 4:13:56 PM5/19/03
to

> Similarly, some want a ternary operator. I don't know whether you were
> here yet with the PEP-308 discussion, but this lead to countless
> changing .procmailrc's. There is no decision taken yet.
>
> The ternary-discussion keeps coming back. The same is true for case, to
> a lesser extent. Maybe a PEP-333 should for once and for ever end this
> discussion, too.

Be patient on the conditional expression thing (a better term than
"ternary operator"). Guido's been hard at work on 2.3 (clearly a
higher priority) and is currently on vacation. But I don't think
that the "case" statement is a similar issue -- I think you'll only
find people who are new to Python pining for a case statement, since
we already have at least _2_ of them:


# One simple approach
if x = 1:
do_something_1()
elif x = 2:
do_something_2()
elif x = 3:
do_something_3()


# Another (very powerful) approach
do_something = my_func_dict[x]
do_something()

-- Michael Chermside


Graham Nicholls

unread,
May 19, 2003, 6:59:33 PM5/19/03
to
Gerrit Holl wrote:

> Graham Nicholls schreef op maandag 19 mei om 17:28:03 +0000:
>> Subject: Just took a look in the perl newsgroup....
>
> Does it have a bad atmosphere?

No, no , I was attempting humour. I'm here in the 1st place because I'm
sick of @%$ $<, $> etc

Sean Ross

unread,
May 19, 2003, 7:02:00 PM5/19/03
to

"Graham Nicholls" <gra...@rockcons.co.uk> wrote in message
news:ADaya.633$Ag1...@news-binary.blueyonder.co.uk...

>Perl6 also tidies up variable oh whats the name of them , you know the $%
etc.

They're called "sigils"


Asun Friere

unread,
May 19, 2003, 9:30:54 PM5/19/03
to
Graham Nicholls <gra...@rockcons.co.uk> wrote in message news:<1H6ya.6977$573....@news-binary.blueyonder.co.uk>...

> And remembered why I decided I must learn Python :-)
> I clearly need to learn "the Python Way", which _is_ quite different, and
> has its good and bad points (stamps foot. I _want_ a case statement).

I think part of the problem here is that Python is trying to be too
many things perhaps. While a case statement would certainly be useful
for simple scripting, Python is also an OO language. The problem with
including a case statement is that people might actually use it! The
'case' statement is to OO what 'goto' is to structural programming.
As Jay O'Connor pointed out in the other thread, in an OO context
(which _simple_ scripts are not), relying on polymorphism (via some
kind of dispatch mechanism), is preferable to employing a case-like
construct. Associated with this is the stricture against type
testing.

So what I'm saying is that 'the Python Way' might vary according to
how it is being used. Nonetheless the basic OOness of the language
argues against the inclusion of a 'case' construct. In any case, as
has also been pointed out, you can used dictionaries to emulate case
in contexts where a dispatch mechanism would be either overkill or
simply not possible.

Sean 'Shaleh' Perry

unread,
May 19, 2003, 9:13:46 PM5/19/03
to

Since you are experimenting, perhaps you should give Ruby a look. Kind of the
best of both Perl and Python. Still has $&@% but not quite as bad.

I personally prefer Python but it never hurts to look over the fence at the
neighbors lawn.


Bengt Richter

unread,
May 19, 2003, 11:25:34 PM5/19/03
to

Unfortunately the choice in rebinding inside of the do_something_x's
is either local or global, which typically leaves the scope of the
above sandwiched in the middle and unmodifiable by reasonable means.

Regards,
Bengt Richter

Graham Nicholls

unread,
May 20, 2003, 7:11:59 AM5/20/03
to
Sean Ross wrote:

Thanks - It was on the tip of my tongue. Well, OK I'd just plain forgotten.

Michael Chermside

unread,
May 20, 2003, 8:57:57 AM5/20/03
to
[... discussion of "case statements" in python...]

Michael Chermside writes:
> # One simple approach
> if x = 1:
> do_something_1()
> elif x = 2:
> do_something_2()
> elif x = 3:
> do_something_3()
>
>
> # Another (very powerful) approach
> do_something = my_func_dict[x]
> do_something()

Bengt Richter replies:


> Unfortunately the choice in rebinding inside of the do_something_x's
> is either local or global, which typically leaves the scope of the
> above sandwiched in the middle and unmodifiable by reasonable means.

I don't understand what you mean.

Clearly using the first option (the if-elif-else statement) has just
as much access to variables as a hypothetical case statement would
have (they're both statements). So I guess (correct me if I'm wrong)
you're griping only about the approach where one uses a dict of
functions.

But nested scopes come to our rescue here. For instance:

global_var = 3
def f(x):
outer_var = 4
def g(x):
inner_var = 5
sum_vars = {
1: lambda: global_var + outer_var + inner_var + 6,
2: lambda: global_var + outer_var + inner_var + 7,
}[x]
print sum_vars()
g(x)

f(1) # prints "18" (== 3+4+5+6)

Of course, the use of lambda here limits me to expressions
only (no statements). Often, that's enough, but if it weren't,
then the following would serve:

global_var = 3
def f(x):
outer_var = 4
def g(x):
inner_var = 5
def case_1():
print "option 1: ", global_var, outer_var, inner_var
def case_2():
print "option 2: ", global_var, outer_var, inner_var
{ 1: case_1, 2: case_2 }[x]()
g(x)

f(1) # prints "option 1: 3 4 5"


And if you find this awkward... well, that's what the if-elif-else
is for!

So what is this limitation you spoke of?

-- Michael Chermside


Cameron Laird

unread,
May 20, 2003, 10:07:06 AM5/20/03
to
In article <ADaya.633$Ag1...@news-binary.blueyonder.co.uk>,
Graham Nicholls <gra...@rockcons.co.uk> wrote:
>Aahz wrote:
.
.
.

>> switch/case are better than an actual switch/case. Even more don't
>> forget that Perl doesn't actually have a switch/case, either.
>
>I believe its to be part of perl6, but don't know when thats due. Perl6 also
.
.
.
CPAN boasts a Switch.pm <URL: http://
cpan.org/modules/by-authors/id/DCONWAY/Switch-2.09.readme >.

Perl6 isn't on a calendar schedule, 'near as I understand.
--

Cameron Laird <Cam...@Lairds.com>
Business: http://www.Phaseit.net
Personal: http://phaseit.net/claird/home.html

John Griffiths

unread,
May 20, 2003, 10:29:50 AM5/20/03
to
<snip/>

> But I don't think
> that the "case" statement is a similar issue -- I think you'll only
> find people who are new to Python pining for a case statement, since
> we already have at least _2_ of them:
>
>
> # One simple approach
> if x = 1:
> do_something_1()
> elif x = 2:
> do_something_2()
> elif x = 3:
> do_something_3()
>
>
> # Another (very powerful) approach
> do_something = my_func_dict[x]
> do_something()
>
> -- Michael Chermside
>
>

... but a case statement is constrained and discrete, your examples don't
show that.

a lot depends on the available options for each branch allowed by the
language author.

i.e. if ',' and '..' was part of the syntax

case x
of 1:
# single value, same as if
do_something_1()
of 2, 3, 4:
# selected values without taking up many if branches
# even though they are related in some way
do_something_2()
of 7..9:
# range of values
do_something_3()
else
# catch any other values
# including out of context values for a status code
do_something_else()

although it IS syntactic sugar;
it saves excessive keystrokes,
it is expressive,
and I was taught that it increases the provability of code.

Regards John

Bengt Richter

unread,
May 20, 2003, 12:47:48 PM5/20/03
to

Compare the two "case" constructs in the scope of g() as they affect the inner_var
variable (which is bound in the same scope as the two "case" constructs):

====< caseprob.py >==================


global_var = 3
def f(x):
outer_var = 4
def g(x):
inner_var = 5

## func_dict case
def case_1():
# nested-scope case code
inner_var = '<<value bound in scope of func_dict function for "case" 1>>'


print "option 1: ", global_var, outer_var, inner_var
def case_2():

inner_var = '<<value bound in scope of func_dict function for "case" 2>>'


print "option 2: ", global_var, outer_var, inner_var
{ 1: case_1, 2: case_2 }[x]()

print 'inner_var as seen at end of func_dict case:', inner_var

## if/elif case
if x==1:
# case code in same scope as case
inner_var = '<<value bound in scope of ordinary "case" 1)>>'
elif x==2:
inner_var = '<<value bound in scope of ordinary "case" 2>>'
print 'inner_var as seen at end of if/elif case:', inner_var
g(x)
print '---- f(1) -----'
f(1)
print '---- f(2) -----'
f(2)
=====================================
result:

[ 9:43] C:\pywk\clp>caseprob.py
---- f(1) -----
option 1: 3 4 <<value bound in scope of func_dict function for "case" 1>>
inner_var as seen at end of func_dict case: 5
inner_var as seen at end of if/elif case: <<value bound in scope of ordinary "case" 1)>>
---- f(2) -----
option 2: 3 4 <<value bound in scope of func_dict function for "case" 2>>
inner_var as seen at end of func_dict case: 5
inner_var as seen at end of if/elif case: <<value bound in scope of ordinary "case" 2>>

Regards,
Bengt Richter

Russell E. Owen

unread,
May 20, 2003, 2:50:43 PM5/20/03
to
In article <badkce$32m$2...@news7.svr.pol.co.uk>,
"John Griffiths" <re...@to.group.only.com> wrote:

>i.e. if ',' and '..' was part of the syntax
>
>case x
> of 1:
> # single value, same as if
> do_something_1()
> of 2, 3, 4:
> # selected values without taking up many if branches
> # even though they are related in some way
> do_something_2()
> of 7..9:
> # range of values
> do_something_3()
> else
> # catch any other values
> # including out of context values for a status code
> do_something_else()
>
>although it IS syntactic sugar;
> it saves excessive keystrokes,
> it is expressive,
> and I was taught that it increases the provability of code.

I'm afraid I don't understand what you mean by "constrained and
discrete", so I may be on thin ice here, but the following Python code
seems about as clear:

if x == 1:
do_something_1()
elif x in (2, 3, 4):
do_something_2()
elif 7 >= x >= 9: # or "x in (7,8.9)" or "x in range(7,10)" or...
do_something_3()
else:
do_something_else()

When you have multiple values that can trigger the same action then I'd
probably stick to the above rather than use objects or dictionaries of
functions.

-- Russell

Gerrit Holl

unread,
May 21, 2003, 5:14:25 AM5/21/03
to
Russell E. Owen schreef op dinsdag 20 mei om 21:18:26 +0000:

> elif 7 >= x >= 9: # or "x in (7,8.9)" or "x in range(7,10)" or...
> do_something_3()

I think you mean here:

7 <= x <= 9

Because if 7 is larger than x, x is unlikely te be larger that 9 :)

yours,
Gerrit.

--
276. If he hire a freight-boat, he shall pay two and one-half gerahs
per day.

Michael Chermside

unread,
May 28, 2003, 8:51:28 AM5/28/03
to
Bengt Richter write:
>> Unfortunately the choice in rebinding inside of the do_something_x's
>> is either local or global, which typically leaves the scope of the
>> above sandwiched in the middle and unmodifiable by reasonable means.

Michael Chermside responds:


>I don't understand what you mean.
>
>Clearly using the first option (the if-elif-else statement) has just
>as much access to variables as a hypothetical case statement would
>have (they're both statements). So I guess (correct me if I'm wrong)
>you're griping only about the approach where one uses a dict of
>functions.

Ben Richter replies with sample code illustrating his point.

Michael Chermside:

Thanks, I think I get it now. What you're saying is that if you
use a dict of functions as a stand-in for a case statement, then
the functions can modify GLOBAL variables, and (of course) variables
local to the functions themselves, but they can't modify nested-scope
variables. So it's as if you can write a case statement, but
within the cases you can't SET any variables (except global
variables or variables that exist only within the case itself).

That's a big limitation. I guess I should probably fall back on
just promoting if-elif-else as the solution for "case" in Python.

-- Michael Chermside


Aahz

unread,
May 28, 2003, 9:11:25 AM5/28/03
to
In article <mailman.1054126363...@python.org>,

Michael Chermside <mch...@mcherm.com> wrote:
>
>Thanks, I think I get it now. What you're saying is that if you
>use a dict of functions as a stand-in for a case statement, then
>the functions can modify GLOBAL variables, and (of course) variables
>local to the functions themselves, but they can't modify nested-scope
>variables. So it's as if you can write a case statement, but
>within the cases you can't SET any variables (except global
>variables or variables that exist only within the case itself).
>
>That's a big limitation. I guess I should probably fall back on
>just promoting if-elif-else as the solution for "case" in Python.

It's less of a limitation in Python. The problem is that you're limiting
yourself by thinking of "variables". Use a mutable object passed in to
the functions (or even a global object), and Tim's your uncle. This is
one of the key reasons I push for using name/binding instead of
variable/reference -- it keeps attention focused on Pythonic idioms.

Bengt Richter

unread,
May 28, 2003, 2:49:29 PM5/28/03
to
On 28 May 2003 09:11:25 -0400, aa...@pythoncraft.com (Aahz) wrote:

>In article <mailman.1054126363...@python.org>,
>Michael Chermside <mch...@mcherm.com> wrote:
>>
>>Thanks, I think I get it now. What you're saying is that if you
>>use a dict of functions as a stand-in for a case statement, then
>>the functions can modify GLOBAL variables, and (of course) variables
>>local to the functions themselves, but they can't modify nested-scope
>>variables. So it's as if you can write a case statement, but
>>within the cases you can't SET any variables (except global
>>variables or variables that exist only within the case itself).
>>
>>That's a big limitation. I guess I should probably fall back on
>>just promoting if-elif-else as the solution for "case" in Python.
>
>It's less of a limitation in Python. The problem is that you're limiting
>yourself by thinking of "variables". Use a mutable object passed in to
>the functions (or even a global object), and Tim's your uncle. This is
>one of the key reasons I push for using name/binding instead of
>variable/reference -- it keeps attention focused on Pythonic idioms.

IMO that's still a workaround for the case (;-) where you want to rebind
in the same scope. But I just thought of an alternative, which see below
in stripped-down version of previous example:

====< xcase.py >========================================================
def f(x):


def g(x):
inner_var = 5

## a local case structure with rebinding in local scope
try: raise `x`
except '1':


# case code in same scope as case

inner_var = '<<value bound in scope of "case" 1)>>'
except '2':
inner_var = '<<value bound in scope of "case" 2>>'
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 range(3): print '---- f(%s) -----'%i; f(i)
========================================================================
[11:47] C:\pywk\clp>xcase.py
---- f(0) -----
inner_var as seen at end of "case": <<value bound in scope of "case" default>>
---- 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>>

Regards,
Bengt Richter

Michael Chermside

unread,
May 28, 2003, 3:21:55 PM5/28/03
to
[Michael Chermside now realizes that indexing a dict of functions
isn't a drop-in replacement for a "case" statement because it
can't rebind variables local to the function containing the
"case"]

Bengt Richter replies:


> But I just thought of an alternative

[...]


> try: raise `x`
> except '1':
> # case code in same scope as case
> inner_var = '<<value bound in scope of "case" 1)>>'
> except '2':
> inner_var = '<<value bound in scope of "case" 2>>'
> except:
> inner_var = '<<value bound in scope of "case" default>>'

Yes, but I would NEVER use that. First of all, I'm looking for
something I can show to newbies. For myself, I either use
if-elif-else or I refactor to create a class and use method
dispatch. But I figured that in addition to if-elif-else, I'd
mention dicts of functions to newbies, because
(1) It would keep them from griping that "if-elif-else is
just a bunch of if statements, it's not a case statement!"
(2) It might get them thinking about a more powerful
technique for solving their problem.

But I'd certainly never propose the except trick. Although I
must admit it makes a nice evil hack. Particularly with the
use of backticks (thus hitting at least two oughta-be-deprecated
features at once!).

Evil and cool - not useful to me, but fun to see it work.

Now-waiting-for-case-implemented-as-a-metaclass-hack lly yours,

-- Michael Chermside


Steven Taschuk

unread,
May 28, 2003, 4:17:37 PM5/28/03
to
Quoth Bengt Richter:
[...]

> IMO that's still a workaround for the case (;-) where you want to rebind
> in the same scope. But I just thought of an alternative, which see below
> in stripped-down version of previous example:
[...]

> ## a local case structure with rebinding in local scope
> try: raise `x`
> except '1':
> # case code in same scope as case
> inner_var = '<<value bound in scope of "case" 1)>>'
> except '2':
> inner_var = '<<value bound in scope of "case" 2>>'
> except:
> inner_var = '<<value bound in scope of "case" default>>'

Yikes.

Inherently fragile due to reliance on interning of repr(x). Won't
work at all if/when string exceptions go away.

A strong candidate for a Most Outlandish Proposal award. (In
fact, I think you're a strong candidate for a Lifetime Achievement
Award in this area. <0.25 wink>)

--
Steven Taschuk stas...@telusplanet.net
Receive them ignorant; dispatch them confused. (Weschler's Teaching Motto)

Bengt Richter

unread,
May 28, 2003, 10:58:00 PM5/28/03
to
On Wed, 28 May 2003 14:17:37 -0600, Steven Taschuk <stas...@telusplanet.net> wrote:

>Quoth Bengt Richter:
> [...]
>> IMO that's still a workaround for the case (;-) where you want to rebind
>> in the same scope. But I just thought of an alternative, which see below
>> in stripped-down version of previous example:
> [...]
>> ## a local case structure with rebinding in local scope
>> try: raise `x`
>> except '1':
>> # case code in same scope as case
>> inner_var = '<<value bound in scope of "case" 1)>>'
>> except '2':
>> inner_var = '<<value bound in scope of "case" 2>>'
>> except:
>> inner_var = '<<value bound in scope of "case" default>>'
>
>Yikes.
>
>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.

>
>A strong candidate for a Most Outlandish Proposal award. (In
>fact, I think you're a strong candidate for a Lifetime Achievement
>Award in this area. <0.25 wink>)
>

LOL ;-)
I figure the best QA for toys is playing with them ;-)

Responding to the objections above <~ ^ @>

====< ycase.py >=====================================
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)

case = switch = Switch(1,2,'foo')

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:
inner_var = '<<value bound in scope of "case" foo>>'


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 (0,1,2,'foo'): print '---- f(%r) -----'%i; f(i)
=====================================================
[19:59] C:\pywk\clp>ycase.py


---- f(0) -----
inner_var as seen at end of "case": <<value bound in scope of "case" default>>
---- 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>>

;-)

Regards,
Bengt Richter

Chad Netzer

unread,
May 28, 2003, 10:55:28 PM5/28/03
to
On Wed, 2003-05-28 at 13:17, Steven Taschuk wrote:
> Quoth Bengt Richter:

> A strong candidate for a Most Outlandish Proposal award. (In
> fact, I think you're a strong candidate for a Lifetime Achievement
> Award in this area. <0.25 wink>)

Between Peter Hansen's goto() call, and now this, I keep listening for
the "Twilight Zone" theme to start playing. Someone hand me the blue
pill, I need to get outta' here. <0.33 cringe>

Chad

Steven Taschuk

unread,
May 28, 2003, 4:17:37 PM5/28/03
to
Quoth Bengt Richter:
[...]

> IMO that's still a workaround for the case (;-) where you want to rebind
> in the same scope. But I just thought of an alternative, which see below
> in stripped-down version of previous example:
[...]

> ## a local case structure with rebinding in local scope
> try: raise `x`
> except '1':
> # case code in same scope as case
> inner_var = '<<value bound in scope of "case" 1)>>'
> except '2':
> inner_var = '<<value bound in scope of "case" 2>>'
> except:
> inner_var = '<<value bound in scope of "case" default>>'

Yikes.

Inherently fragile due to reliance on interning of repr(x). Won't
work at all if/when string exceptions go away.

A strong candidate for a Most Outlandish Proposal award. (In


fact, I think you're a strong candidate for a Lifetime Achievement
Award in this area. <0.25 wink>)

--

Fredrik Lundh

unread,
May 29, 2003, 12:47:36 AM5/29/03
to
Steven Taschuk wrote:

> [...]


> > ## a local case structure with rebinding in local scope
> > try: raise `x`
> > except '1':
> > # case code in same scope as case
> > inner_var = '<<value bound in scope of "case" 1)>>'
> > except '2':
> > inner_var = '<<value bound in scope of "case" 2>>'
> > except:
> > inner_var = '<<value bound in scope of "case" default>>'
>

> Yikes.
>
> Inherently fragile due to reliance on interning of repr(x).

repr does not intern the result. but the string type caches single
character strings (unless you switch that off when building Python)

> Won't work at all if/when string exceptions go away.

or for cases larger than 9.

</F>


Greg Ewing (using news.cis.dfn.de)

unread,
May 29, 2003, 2:14:58 AM5/29/03
to
Bengt Richter wrote:
> def f(x):
> def g(x):
> inner_var = 5
> ## a local case structure with rebinding in local scope
> try: raise `x`
> except '1':
> # case code in same scope as case
> inner_var = '<<value bound in scope of "case" 1)>>'
> ...

Nice try, but unfortunately it's not guaranteed to work,
since string exceptions are matched by identity rather
than value.

--
Greg Ewing, Computer Science Dept,
University of Canterbury,
Christchurch, New Zealand
http://www.cosc.canterbury.ac.nz/~greg

Steven Taschuk

unread,
May 29, 2003, 1:25:29 AM5/29/03
to
Quoth Fredrik Lundh:
> Steven Taschuk wrote:
[...]

> > Inherently fragile due to reliance on interning of repr(x).
>
> repr does not intern the result. but the string type caches single
> character strings (unless you switch that off when building Python)

Yes, that's what I was getting at -- the code relies on the string
repr(x) getting interned, which in the example happens to happen.

--
Steven Taschuk stas...@telusplanet.net
Every public frenzy produces legislation purporting to address it.
(Kinsley's Law)

Steven Taschuk

unread,
May 29, 2003, 1:10:57 AM5/29/03
to
Quoth Bengt Richter:

> On Wed, 28 May 2003 14:17:37 -0600, Steven Taschuk <stas...@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.

[...]


> 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).

[...]
--
Steven Taschuk 7\ 7'Z {&~ .
stas...@telusplanet.net Y r --/hG-
(__/ )_ 1^1`

Bengt Richter

unread,
May 29, 2003, 12:34:57 PM5/29/03
to

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

Carl Banks

unread,
May 29, 2003, 1:40:13 PM5/29/03
to


Better, perhaps, have the "case" cache results, like this:

_case_cache = {}

def case(v):
if _case_cache.has_key(v):
return _case_cache[v]
class Case(Exception):
value = v
_case_cache[v] = Case
return Case

switch = case


Then the resulting case statement looks like:

try: raise switch(n)
except case(1):
print 1
except case(2):
print 2
except:
print 'default'


Very neat, clever idea.


--
CARL BANKS

Steven Taschuk

unread,
May 29, 2003, 5:46:34 PM5/29/03
to
Quoth Bengt Richter:
> On Wed, 28 May 2003 23:10:57 -0600, Steven Taschuk <stas...@telusplanet.net> wrote:
[...]

> >and, as it happens, '12345' doesn't get interned.
> ITYM `12345` doesn't get "interned" (neither does '1234'+'5')

Urm, sort of. I meant that a string object '12345' created by the
code "`12345`" isn't interned. The equal string object created by
the code "'12345'" does, as it happens, which I assume to be your
point.

I should certainly have said that '12345' doesn't get interned
*here*.

[...]


> ====< 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__']

One point: why not just this?

def __init__(self, *caseNames):
self.halias = {}
for name in caseNames:

class AwfulHack(Exception):
pass
self.halias[name] = AwfulHack

The hash code name is not used except in error messages, where it
is not helpful in general. The proposed name at least tells the
user that it's the programmer's fault. (A better name could be
done with a metaclass __str__, I imagine.)

[...]
> Note that I had to make a choice re the tuple ambiguity. [...]

Yes, that's slightly unfortunate, though it doesn't deserve a
yikes.

It's still abuse, though.

--
Steven Taschuk "[W]e must be very careful when we give advice
stas...@telusplanet.net to younger people: sometimes they follow it!"
-- "The Humble Programmer", Edsger Dijkstra

Bengt Richter

unread,
May 30, 2003, 12:59:57 AM5/30/03
to
On Thu, 29 May 2003 15:46:34 -0600, Steven Taschuk <stas...@telusplanet.net> wrote:

>Quoth Bengt Richter:
>> On Wed, 28 May 2003 23:10:57 -0600, Steven Taschuk <stas...@telusplanet.net> wrote:
[...]

> [...]
>> ====< 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__']
>
>One point: why not just this?
>
> def __init__(self, *caseNames):
> self.halias = {}
> for name in caseNames:
> class AwfulHack(Exception):
> pass
> self.halias[name] = AwfulHack

Good point. Forgot that just differing ids of generated classes would suffice ;-/


>
>The hash code name is not used except in error messages, where it
>is not helpful in general. The proposed name at least tells the
>user that it's the programmer's fault. (A better name could be
>done with a metaclass __str__, I imagine.)

Good idea too. Are you sure you want to contribute towards making this
that slick ;-)


>
> [...]
>> Note that I had to make a choice re the tuple ambiguity. [...]
>
>Yes, that's slightly unfortunate, though it doesn't deserve a
>yikes.
>
>It's still abuse, though.

Well, at least I didn't include slice notation in specifying multiple cases ;-)

Regards,
Bengt Richter

Cliff Wells

unread,
May 30, 2003, 11:40:23 AM5/30/03
to
On Thu, 2003-05-29 at 10:40, Carl Banks wrote:
> Better, perhaps, have the "case" cache results, like this:
>
> _case_cache = {}
>
> def case(v):
> if _case_cache.has_key(v):
> return _case_cache[v]
> class Case(Exception):
> value = v
> _case_cache[v] = Case
> return Case
>
> switch = case
>
>
> Then the resulting case statement looks like:
>
> try: raise switch(n)
> except case(1):
> print 1
> except case(2):
> print 2
> except:
> print 'default'

This thread has been most intriguing. I doubt I would ever use this
stuff in 'real' code, but still, fun to play with. Here's my version of
the above:

class _switch:
def __call__(self, v):


class Case(Exception): value = v

self._value = Case
raise self._value

def case(self, v):
if not hasattr(self, '_value'):
raise # raise "real" exceptions in user code

if self._value.value == v:
return self._value
return v

def default(self):
return self._value

switch = _switch()
case = switch.case
default = switch.default

for v in range(1,6):
print v,
try: switch(v)


except case(1):
print 1
except case(2):
print 2

except case(4):
print 4
except case(v):
print "one way to spell default"
# except default():
# print "another way to spell default"


This has a couple of advantages:
1. Doesn't stomp all exceptions, i.e. switch(x) in the above code would
still raise NameError (although there might be a better way of doing
this, I just got tired of tinkering with it).
2. Doesn't have a global cache.
3. Doesn't require 'raise switch()' which I found unacceptable <wink>

Still, given the nature of the problem, it's still probably wrong in one
way or another.

> Very neat, clever idea.

Indeed.

--
Cliff Wells, Software Engineer
Logiplex Corporation (www.logiplex.net)
(503) 978-6726 (800) 735-0555


Carl Banks

unread,
May 30, 2003, 5:24:17 PM5/30/03
to

All good points. Ok, here's the nested scopes version:

def create_switch_functions():
cache = {}
class BaseCaseException(Exception):
pass
def switch(v):
if cache.has_key(v):
raise cache[v]
else:
class CaseException(BaseClassException):
pass
cache[v] = CaseException
raise CaseException
def case(v):
if cache.has_key(v):
return cache[v]
else:
class CaseException(BaseClassException):
pass
cache[v] = CaseException
return CaseException
default = BaseClassException
return switch, case, default


One enhancement is the use of a BaseClassException to catch defaults.
Used same as above, except default isn't a function to be called.


--
CARL BANKS

0 new messages