[Jay Bloodworth <johnabloodwor...@gmail.com>]
> Does anybody have a nice, student friendly explanation of the
> "half-open" semantics of the range function and of slice notation? In
> other words, why does the list created by range(0,10) contain 0 as an
> element but not 10, and why does mylist[0:10] start with mylist[0] and
> end with mylist[9]? If you're an experienced coder, these semantics make
> sense in terms of the underlying implementation and the usual use of
> these objects as iterators, but if lists are new to you the behavior can
> seem a little mysterious. Thoughts?

It's easiest to picture sequence indices as pointing _between_
sequence items rather than _at_ them.  That's why there are N+1
meaningfully different indices into a sequence with N items.  For
example, for sequence A B C:

0 A 1 B 2 C 3

Now, e.g., "it's obvious" that 1:3 spans B and C, and 2:2 is an empty
sequence.  That slice lo:hi, with 0 <= lo <= hi and in bounds, yields
a (sub)sequence with hi-lo elements, also prevents oodles of "off by
1" errors.  It's just a convention that the non-slicing seq[i]
notation refers to the sequence element "to the right" of i.  It
_could_ have referred to the one "to the left" instead, but "to the
right' makes it consistent with C (all languages with 0-based array
indexing).

`range()` is related to this, but also driven by mathematical
elegance.  For lo <= k <= hi,

list(range(lo:hi)) == list(range(lo:k)) + list(range(k:hi))

This is a very pleasant decomposition when, e.g,, developing inductive
proofs of algorithm correctness as a loop marches over a sequence.
When the loop index is i, at the start of the loop seq[0:i] has
already been processed, and seq[i:] has yet to be done.  No "off by 1"
errors sneak in there either.
_______________________________________________
Edu-sig mailing list -- edu-sig@python.org
To unsubscribe send an email to edu-sig-le...@python.org
https://mail.python.org/mailman3/lists/edu-sig.python.org/

Reply via email to