Python synergies in list addressing
Something I took from this Ian Bicking entry is that synergies and elegance don't just happen; someone usually worked hard to make it all come out neatly. Python lists have an interesting case of this; some apparently odd decisions in other places turn out to be needed to create useful (and error-avoiding) synergies.
Python lists (and sequences in general) are indexed from 0. Zero-based
indexing presents a problem, which can be succinctly stated as this:
list element indexes run from 0 to len(lst)-1
. That -1
is ugly
and error prone.
So Python has quietly arranged things so that you never have to write it
(or +1
, its kissing cousin), by making 'slice' addressing of lists and
range()
end-exclusive asymmetric (instead of 'i:j
' running from i
to j
, it runs from i
to j-1
). This means:
range(len(lst))
generates indexes that exactly cover the list, since they run from 0 tolen(lst)-1
.lst[:len(lst)]
is the entire list.- if
pref
is at the start of the list,lst[len(pref):]
is the list withpref
removed from the start. - if
sublst
is inlst
starting atpos
,lst[:pos]
is everything beforesublst
andlst[pos + len(sublst):]
is everything aftersublst
. - if
suf
is at the end oflst
,lst[:-len(suf)]
is the list withsuf
removed from the end. - avoiding a subtler error,
lst[len(pref):]
works even ifpref
is zero length (althoughlst[:-len(suf)]
does not; can't win them all).
All of these are straightforward expressions, with nary a stray -1
or +1
in sight and no chance for off by one errors. (Is it elegant
or does the asymmetry cancel out the lack of +1
and -1
? That's in
the eye of the beholder, but I like it.)
Python is not the first language to notice this issue; Scheme's
substring
is end-exclusive, for example. Other things duck the issue
by having their substring operation take a start and a length, instead
of a start and and end position.
(This entry's genesis came from comments made on AClosureConfusion.)
|
|