more fun with PEP 276

James_Althoff at i2.com James_Althoff at i2.com
Thu Dec 6 22:57:39 CET 2001


Jeff Shannon wrote:
<snip>
>If you *always* have half-open intervals (in the same direction), then you
will
>know, almost without thinking about it, which way any corrections have to
be
>made.  If you sometimes have half-open, sometimes closed, sometimes
>reversed-half-open, sometimes fully open, etc... then you will constantly
be
>having to check what you're doing in *this* case, look back at what you've
>done, think through in detail what the effects are, etc, etc.  (There
should be
>one, and preferably *only* one, obvious way to do it.)
<snip>
>In most cases, I'd expect the underlying source of the data to behave
according
>to 0-based half-open intervals.  If it doesn't, I'd correct it at the
>interface, instead of in the range()--
>
>left = getLeftSide() - 1
>right = getRightSide() - 1
>for i in range(left, right):   ...
>
>Not perfect, perhaps, but at least explicit.
<snip>
>They are *always* the same, therefore no visual mechanism is needed.  The
fact
>that it says "range" tells me that it's closed left and open right.  I
don't
>have to worry about any other possibility.
<snip>
>This is a recipe for confusion.  If you can't rely on the half-open
interval
>being always the same, then it *will* bite you eventually, and a lot worse
than
>people currently get bit by range()'s behavior (which is at least
predictable).

Yes, "closed on the left, open on the right" intervals are very common.  In
fact, that is what helped motivate PEP 276 -- making it *really* easy to
deal with such intervals when accessing items in a structure by index:

for i in table.rowcount:
    for j in table.colcount:
        print table.value(i,j)

Here, i and j both use "closed on the left, open on the right" intervals (0
to "len"-1).

But "very common" is not "always" and some of the posters in the PEP 276
thread seemed to be interested in making it more convenient and *explicit*
when one deals with other types of intervals.  As in, for example, David
Eppstein's:

for n > i >= 0:
    for i < j <= n:
        if i == j-1:
            V[i,j] = id
        else:
            V[i,j] = min([q(i,k,j) @ V[i,j] @ V[j,k] for i < k < j])

or the equivalent:

for i in n > ... >= 0:
    for j in i < ... <= n:
        if i == j-1:
            V[i,j] = id
        else:
            V[i,j] = min([q(i,k,j) @ V[i,j] @ V[j,k] for k in i < ... < j])


I believe that many Python users think it would be good to have some
mechanism that is *more explicit* than range/xrange when dealing with
intervals.  I don't think

    -5 // span // 5

is the ideal syntax.  I think it would be much better if one could write:

    -5 <= ... <= 5

I would like to see a class Interval (named IteratorBounds in my posted
example implementation) that contains start, stop, step, left, and right
values where you could create interval instances using the syntax of
relational operators.  Such intervals could be specified in any context
where expressions are valid and would yield iterators in for-loops and
other places where iterators are called for.  Python, as is, doesn't
support this (unless I'm missing something).  So I showed how this could be
approximated with the  -5 // span // 5  equivalent.  I found it very handy
when playing around with it.  Again, if -5 <= ... <= 5 could be made to
work, it would be *really* nice (in my view).

Even for "closed on the left, open on the right" intervals I would prefer:

for i in ... < table.rowcount:
    for j in ... < table.colcount:
        print table.value(i,j)

over:

for i in xrange(table.rowcount):  # yes, I have a *lot* of rows
    for j in range(table.colcount):
        print table.value(i,j)


Jim






More information about the Python-list mailing list