PEP 308: an additional "select/case" survey option
Clark C. Evans
cce at clarkevans.com
Tue Mar 4 21:47:53 EST 2003
After some encouragement by Raymond, I'd like to add one more
item to the survey, if you like what follows perhaps you can
even *change* your vote (Raymond?) to include:
Q accept switch-case
Z deny everything else!
Dedication:
To those who hate the terinary operator beacuse it isn't pythonic...
Background:
After looking over much of my Python source code, I found that
where I thought I needed a terinary operator, I ended
up taking one of two paths:
if 0 == quantity: exit = 'no exit'
elif 1 == quantity: exit = 'a door'
else: exit = '%s doors' % quantity
Or, the more concise mapping-idiom:
exit = { 0: 'no exit',
1: 'a door' }.get(quantity,
'%s doors' % quantity)
The latter construct has two advantages over the if/else
statement level solution:
1. It's clear that I'm making an assignment to exit;
in effect the "exit =" isn't duplicated and this
aids in authoring/maintenance/reading.
2. The ugly '== quantity' isn't duplicated for each line,
once again improving maintenance.
However, the mapping-idiom has three problems:
1. The conditional switch isn't exactly "obvious" here
unless you're a Python vetran, this hurts in the
maintenance arena; besides the 'else' case is ugly.
2. It doesn't short-circut cleanly, to do a short-circut
you need to use lambda's... ick; further, it results in
the construction of a mapping which may not really help
out optimizations.
3. It really doesn't facilitate the use whitespace/indentation
to re-inforce a visual representation of the program's
structure.
Philosophy:
The whole rationale for this construct is to reduce data
duplication (both the assignments and conditional tests)
to increase maintenance.
The goal is not to save on vertical screen realistate by
enabling multi-line constructs to be "jumbled" into a
single line. It seems that many people are asking for the
terinary option for the latter.
Instead, this proposal seeks to engage Python's unique approach
to syntax by using whitespace to enhance the visual representation
of the program's structure. Many Python converts are here exactly
beacuse Python is very readable and thus maintainable. This proposal
is here soley to re-enforce this "pythonic" approach to coding.
Proposal:
The proposal introduces a 'select' or 'switch' keyword which creates
an indented expression block. Instead of the following,
exit = { 0: 'no exit',
1: 'a door' }.get(quantity,
'%s doors' % quantity)
You could write,
exit = select quantity
case 0: 'no exit'
case 1: 'a door'
else: '%s doors' % quantity
This proposal gives you the power of the mapping-idiom without
the uglyness. It expresses the intent of the construct in a
very human readable manner using whitespace smartly.
While the above is "good", it assumes an equality operator. So
that the structure is more generic, his proposal allows an optional
operator (a function taking 2 or more value and returning a boolean)
immediately following the 'case' label,
z = 1.0 + select abs(z)
case < .0001: 0
case > .5: .5
else: -sigma / (t + 1.0)
Note that the examples given in the proposal are thus
very easily expressed using this notion:
data = select hasattr(s,'open')
case true: s.readlines()
else: s.split()
z = 1.0 + select abs(z)
case < .0001: 0
else: z
t = v[index] = select t
case <= 0: t - 1.0
else: -sigma / (t + 1.0)
return select len(s)
case < 10: linsort(s)
else: qsort(s)
The 'operator' need not be binary, one could, for example,
provide a terinary operator, such as:
def between(cmp,rhs,lhs): return cmp >= rhs and cmp <= lhs
score = select die
case 1: -2
case 2: -1
case between 3,4: 0
case 5: +1
case 6: +2
else: raise "invalid die roll %d " % roll
Summary:
The proposal thus creates a flexible mechanism for avoiding
the excessive duplication of assignment and equality fragments
within a conditional assignment nest; it does so through a
new expression structure which, like the rest of Python, uses
indentation for structure.
This proposal thus provides the pratical benefit of a terinary
operator, while at the same time opening the door to a rich
(and quite readable) conditional assignment mechanism.
In particular, this proposal rejects the rationale for 'terinary'
operator as a way to trade horizontal screen realestate for
vertical space; as this rationale is in direct opposition to
the fundamental principle of readability. And as such, the
proposal explicitly does not include a way to include multiple
case labels on the same line.
Credits:
Alex Martelli for validating the elimination of needless-duplication
of code as the primary goal for the construct; and
Carel Fellinger for presenting the idea of a plugable predicate/operator
Raymond Hettinger for asking me to write this up more or less formally
More information about the Python-list
mailing list