Towards a more Pythonic "Ternary Operator"

Clark C. Evans cce at clarkevans.com
Tue Mar 4 06:01:03 EST 2003


After looking over my code some, I found that where
I thought I needed a terinary operator, I ended
up taking one of two paths:

  exit = { 0: 'no exit', 
           1: 'a door' }.get(quantity,
          '%s doors' % quantity)

Or, the more 'obvious' ...

  if   0 == quantity:  exit = 'no exit'
  elif 1 == quantity: exit = 'a door'
  else: exit = '%s doors' % quantity

The first construct has two advantages over the more 'obvious'
solution:

  1. It's clear that I'm making an assignment to exit
  2. I don't have to duplicate the ugly '== quantity'
     each time.

However, the first construct brings with it two problems:

  1. The 'else' case is kinda ugly.
  2. It doesn't short-circut cleanly, to have the short-circut
     behavior you need to use lambda's as the mapping values
     and then invoke the result...

So, if you asked me, what I'd like is a hybrid of the two options
above, a nicer-looking short-circuting in-line mapping:

  exit = select quantity 
           case 0: 'no exit'
           case 1: 'a door'
           else: '%s doors' % quantity
  
  #NOTE: new lines/indentation is mandatory in this proposal

IMHO, the other options in the survey are quite clean
when you look at it this way:

  data = select hasattr(s,'open') 
           case true: s.readlines() 
           else: s.split()

  z = 1.0 + select abs(z) < .0001 
              case true: 0
              else: z

  t = v[index] = select t <= 0 
                   case true: (t-1.0) 
                   else: -sigma / (t + 1.0)

  return select len(s) < 10
           case true: linsort(s)
           else: qsort(s)

...

The other advantage of this mechanism is that the 
semantics could be made a bit more flexible by requiring
the case item to be a predicate -- a boolean function 
with one argument, the item being selected upon.  Thus,

z = 1.0 + select abs(z)
            case lt(.0001): 0
            case gt(.5): .5
            else: -sigma / (t + 1.0)
                 
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

Since the items 1,2,5,6 arn't predicates, then the
"equal" predicate is assumed.  

Now... _this_ I would really find useful.

Best,

Clark





More information about the Python-list mailing list