PEP 308: some candidate uses cases from live code

Bengt Richter bokr at oz.net
Sun Feb 9 13:37:48 CET 2003


On Sun, 9 Feb 2003 08:10:17 +0000 (UTC), Martin Maney <maney at pobox.com> wrote:

>Okay, a bleary-eyed survey of about 4000 lines of code from a project
>I've been working on in odd bits of time.  Best Available Data, sir,
>but mine own.  <wink>
>
>These are the uses of a simple if/else that seemed to me to be at least
>vaguely suitable for the proposed ternary operator; most of the if/else
>occurences rejected were over four lines or had very little in common
>between the if and the else code.  I don't believe I omitted any that
>weren't less good candidates than the ones below.
>
>If you think my commentary reveals an imperfectly consistent view of
>the proper use and value of 308's ternary, you may be right.  I worked
>on this intermittently over the last few hours, and I haven't gone back
>and "corrected" anything [though I may add a note like this before I
>send this off] just because I was learning how I liked this as I went
>along.
>
>
>Candidate 1 - this is from a simple "one line == one record" CSV parser
>
>        else:
>            start = i
>            j = s.find(',', i)
>            if j >= 0:
>                i = j
>            else:
>                i = n
>            field = s[start:i]
>
>    About all that could be changed here is collapsing the if/else, as i is
>    live past the end of the code shown:
>
>        else:
>            start = i
>            j = s.find(',', i)
             field = s[start:(j<0?j,n)]  # cond ? false_sel, true_sel

>            i = j if j >= 0 else n
>            field = s[start:i]
>
>    I don't find this very convincing, but it has its points.  I wrote it so
>    as to keep the condition the same, and it's just coincidence that that
>    made it come out with the pleasing "j if j >= 0 ..." form.  At least I
>    find it pleasing.  Is that line harder to understand than any one of the
>    original lines?  Of course.  Is it harder to understand than the total
>    effect of the four lines it replaces?
>
>
>Candidate 2 - generating bounding dates for a month
>
>        first = '%04d-%02d-01' % (year, month)
         last = '%04d-%02d-01' %  (month<12? (year+1, 1), (year, month+1))

>        if (month < 12):
>            last = '%04d-%02d-01' % (year, month + 1)
>        else:
>            last = '%04d-01-01' % (year + 1)
>
>    Not really a very promising candidate: there's too much that's different
>    between the two values for this to appeal to me.  This was the second
>    plausible candidate I found after sifting through a lot of Python with
>    no simple if/else constructs.  Of course a lot of the code I've been
>    looking at was written knowing that ternary wasn't a viable option (I
>    have used one or another of the kulges a few times, but generally find
>    them uglier than four not-quite-emtpy lines of code.)
>
>
>Candidate 3 - calculate "school year" from year & month
>
>        if d0.month < 7:
>            sy = d0.year - 1
>        else:
>            sy = d0.year
>
>    Becomes, after a little rearrangement:
>
>        sy = d0.year - (1 if d0.month < 7 else 0)
         sy = d0.year - (d0.month < 7) # this is already 1 or 0

         sy = d0.year - (d0.month < 7 ? 0, 1) # this is already 1 or 0
         sy = d0.month<7 ? d0.year, d0.year-1 # alternative form

>
>    I think this actually expresses the original logic a little more
>    clearly: the school year is the day's year unless the day's month is
>    January through June; then one must be subtracted to get the calendar
>    year during which the school year began.
>
>
>Candidate 4 - preparing to use an optional parameter in generated HTML
>
>        if params.has_key('add2url'):
>            add2url = '?' + params['add2url']
>        else:
>            add2url = ''
>
>    Could be expressed as
>
>        add2url = '?' + params['add2url'] if params.has_key('add2url') else ''
           
         add2url = params.has_key('add2url') ? '', '?'+params['add2url']

>
>    This is an example where the short-circuit behavior is important, but
>    it's not a terribly convincing example overall since it could easily
>    be written as
>
>        add2url = ''
>        if params.has_key('add2url'):
>            add2url = '?' + params['add2url']
>
>    This last is almost certainly how I would write this, as there's no
>    concrete advantage IMO to the ternary form here.  I think I was using
>    a common pattern for all setup items in this routine and/or module.
>
>    [later: "certainly"?  well, maybe, but maybe not]
>
>
>Candidate 5 - another bit from HTML generation
>
>        if len(events) > 1:
>            sep = ' '
>        else:
>            sep = '<br>'
>
>    Obvious:
>
>        sep = ' ' if len(events) > 1 else '<br>'
         sep = len(events) > 1 ? '<br>', ' '
>
>    In a larger context, this would actually allow me to do away with the
>    'sep' temporary:
>
>        if len(events) > 1:
>            sep = ' '
>        else:
>            sep = '<br>'
>        ...
>        if tail:
>            tail = sep + tail
>
>    allowing a considerable reduction:
>
>        ...
>        if tail:
>            tail = (' ' if len(events) > 1 else '<br>') + tail
             tail = (len(events) > 1 ? '<br>', ' ') + tail
>
>    I'm not sure why the calculation of 'sep' was separated from its use
>    in the code.  This is older code that's been through a couple waves of
>    refactorings of the system its part of; possibly 'sep' used to be used
>    in more than one location in an earlier version.  Perhaps the inlined
>    version above should be compared to this rather than the original:
>
>        ...
>        if tail:
>            if len(events) > 1:
>                tail = ' ' + tail
>            else:
>                tail = '<br>' + tail
>
>
>Candidate 6 - again, HTML generation
>
>        if colors:
>            color = 'bgcolor=%s' % colors[gr % len(colors)]
>        else:
>            color = ''
>
>    Naturally:
>
>        color = 'bgcolor=%s' % colors[gr % len(colors)] if colors else ''
         color = colors? '', 'bgcolor=%s' % colors[gr % len(colors)]
>
>    Hmmm... what precedence does ternary have, again?  The previous item
>    just seemed to obviously need the parens; this one I'm not so sure
>    about.
>
>
>Summary:
>
>    I didn't find nearly as many simple if/else uses as I had expected to
>    in this project's code.  What else have I been working on recently that
>    might account for this persistent notion that I ought to have better
>    examples than most of these?
>
>    The other thing I discovered was that some of the older modules really
>    need a good, brisk currying - I came across a few things that made me
>    wince.  Oh, and Aahz, I know you'll want to hear about this: a couple
>    modules with some map'n'filter'n'lambda uses that I'm certain will look
>    a lot better as list comprehensions.  :-)
>
>    Amazing how dated six month old code can look...
>

Regards,
Bengt Richter




More information about the Python-list mailing list