Skip to content

Commit

Permalink
This is my nearly two year old patch
Browse files Browse the repository at this point in the history
[ 400998 ] experimental support for extended slicing on lists

somewhat spruced up and better tested than it was when I wrote it.

Includes docs & tests.  The whatsnew section needs expanding, and arrays
should support extended slices -- later.
  • Loading branch information
Michael W. Hudson committed Jun 11, 2002
1 parent f90ae20 commit 5efaf7e
Show file tree
Hide file tree
Showing 13 changed files with 570 additions and 22 deletions.
26 changes: 26 additions & 0 deletions Doc/api/concrete.tex
Expand Up @@ -2288,6 +2288,32 @@ \subsection{Slice Objects \label{slice-objects}}

\begin{cfuncdesc}{int}{PySlice_GetIndices}{PySliceObject *slice, int length,
int *start, int *stop, int *step}
Retrieve the start, stop and step indices from the slice object
\var{slice}, assuming a sequence of length \var{length}. Treats
indices greater than \var{length} as errors.

Returns 0 on success and -1 on error with no exception set (unless one
of the indices was not \constant{None} and failed to be converted to
an integer, in which case -1 is returned with an exception set).

You probably do not want to use this function. If you want to use
slice objects in versions of Python prior to 2.3, you would probably
do well to incorporate the source of \cfunction{PySlice_GetIndicesEx},
suitably renamed, in the source of your extension.
\end{cfuncdesc}

\begin{cfuncdesc}{int}{PySlice_GetIndicesEx}{PySliceObject *slice, int length,
int *start, int *stop, int *step,
int *slicelength}
Usable replacement for \cfunction{PySlice_GetIndices}. Retrieve the
start, stop, and step indices from the slice object \var{slice}
assuming a sequence of length \var{length}, and store the length of
the slice in \var{slicelength}. Out of bounds indices are clipped in
a manner consistent with the handling of normal slices.

Returns 0 on success and -1 on error with exception set.

\versionadded{2.3}
\end{cfuncdesc}


Expand Down
49 changes: 34 additions & 15 deletions Doc/lib/libstdtypes.tex
Expand Up @@ -433,6 +433,7 @@ \subsection{Sequence Types \label{typesseq}}
\hline
\lineiii{\var{s}[\var{i}]}{\var{i}'th item of \var{s}, origin 0}{(2)}
\lineiii{\var{s}[\var{i}:\var{j}]}{slice of \var{s} from \var{i} to \var{j}}{(2), (3)}
\lineiii{\var{s}[\var{i}:\var{j}:\var{k}]}{slice of \var{s} from \var{i} to \var{j} with step \var{k}}{(2), (4)}
\hline
\lineiii{len(\var{s})}{length of \var{s}}{}
\lineiii{min(\var{s})}{smallest item of \var{s}}{}
Expand All @@ -446,6 +447,7 @@ \subsection{Sequence Types \label{typesseq}}
\indexii{repetition}{operation}
\indexii{subscript}{operation}
\indexii{slice}{operation}
\indexii{extended slice}{operation}
\opindex{in}
\opindex{not in}

Expand Down Expand Up @@ -492,6 +494,15 @@ \subsection{Sequence Types \label{typesseq}}
\code{len(\var{s})}, use \code{len(\var{s})}. If \var{i} is omitted,
use \code{0}. If \var{j} is omitted, use \code{len(\var{s})}. If
\var{i} is greater than or equal to \var{j}, the slice is empty.

\item[(4)] The slice of \var{s} from \var{i} to \var{j} with step \var{k}
is defined as the sequence of items with index \code{\var{x} =
\var{i} + \var{n}*\var{k}} such that \var{n} \code{>=} \code{0} and
\code{\var{i} <= \var{x} < \var{j}}. If \var{i} or \var{j} is
greater than \code{len(\var{s})}, use \code{len(\var{s})}. If
\var{i} or \var{j} are ommitted then they become ``end'' values
(which end depends on the sign of \var{k}).

\end{description}


Expand Down Expand Up @@ -875,31 +886,36 @@ \subsubsection{Mutable Sequence Types \label{typesseq-mutable}}
{slice of \var{s} from \var{i} to \var{j} is replaced by \var{t}}{}
\lineiii{del \var{s}[\var{i}:\var{j}]}
{same as \code{\var{s}[\var{i}:\var{j}] = []}}{}
\lineiii{\var{s}[\var{i}:\var{j}:\var{k}] = \var{t}}
{the elements of \code{\var{s}[\var{i}:\var{j}:\var{k}]} are replaced by those of \var{t}}{(1)}
\lineiii{del \var{s}[\var{i}:\var{j}:\var{k}]}
{removes the elements of \code{\var{s}[\var{i}:\var{j}:\var{k}]} from the list}{}
\lineiii{\var{s}.append(\var{x})}
{same as \code{\var{s}[len(\var{s}):len(\var{s})] = [\var{x}]}}{(1)}
{same as \code{\var{s}[len(\var{s}):len(\var{s})] = [\var{x}]}}{(2)}
\lineiii{\var{s}.extend(\var{x})}
{same as \code{\var{s}[len(\var{s}):len(\var{s})] = \var{x}}}{(2)}
{same as \code{\var{s}[len(\var{s}):len(\var{s})] = \var{x}}}{(3)}
\lineiii{\var{s}.count(\var{x})}
{return number of \var{i}'s for which \code{\var{s}[\var{i}] == \var{x}}}{}
\lineiii{\var{s}.index(\var{x})}
{return smallest \var{i} such that \code{\var{s}[\var{i}] == \var{x}}}{(3)}
{return smallest \var{i} such that \code{\var{s}[\var{i}] == \var{x}}}{(4)}
\lineiii{\var{s}.insert(\var{i}, \var{x})}
{same as \code{\var{s}[\var{i}:\var{i}] = [\var{x}]}
if \code{\var{i} >= 0}}{(4)}
if \code{\var{i} >= 0}}{(5)}
\lineiii{\var{s}.pop(\optional{\var{i}})}
{same as \code{\var{x} = \var{s}[\var{i}]; del \var{s}[\var{i}]; return \var{x}}}{(5)}
{same as \code{\var{x} = \var{s}[\var{i}]; del \var{s}[\var{i}]; return \var{x}}}{(6)}
\lineiii{\var{s}.remove(\var{x})}
{same as \code{del \var{s}[\var{s}.index(\var{x})]}}{(3)}
{same as \code{del \var{s}[\var{s}.index(\var{x})]}}{(4)}
\lineiii{\var{s}.reverse()}
{reverses the items of \var{s} in place}{(6)}
{reverses the items of \var{s} in place}{(7)}
\lineiii{\var{s}.sort(\optional{\var{cmpfunc}})}
{sort the items of \var{s} in place}{(6), (7)}
{sort the items of \var{s} in place}{(7), (8)}
\end{tableiii}
\indexiv{operations on}{mutable}{sequence}{types}
\indexiii{operations on}{sequence}{types}
\indexiii{operations on}{list}{type}
\indexii{subscript}{assignment}
\indexii{slice}{assignment}
\indexii{extended slice}{assignment}
\stindex{del}
\withsubitem{(list method)}{
\ttindex{append()}\ttindex{extend()}\ttindex{count()}\ttindex{index()}
Expand All @@ -908,32 +924,35 @@ \subsubsection{Mutable Sequence Types \label{typesseq-mutable}}
\noindent
Notes:
\begin{description}
\item[(1)] The C implementation of Python has historically accepted
\item[(1)] \var{t} must have the same length as the slice it is
replacing.

\item[(2)] The C implementation of Python has historically accepted
multiple parameters and implicitly joined them into a tuple; this
no longer works in Python 2.0. Use of this misfeature has been
deprecated since Python 1.4.

\item[(2)] Raises an exception when \var{x} is not a list object. The
\item[(3)] Raises an exception when \var{x} is not a list object. The
\method{extend()} method is experimental and not supported by
mutable sequence types other than lists.

\item[(3)] Raises \exception{ValueError} when \var{x} is not found in
\item[(4)] Raises \exception{ValueError} when \var{x} is not found in
\var{s}.

\item[(4)] When a negative index is passed as the first parameter to
\item[(5)] When a negative index is passed as the first parameter to
the \method{insert()} method, the new element is prepended to the
sequence.

\item[(5)] The \method{pop()} method is only supported by the list and
\item[(6)] The \method{pop()} method is only supported by the list and
array types. The optional argument \var{i} defaults to \code{-1},
so that by default the last item is removed and returned.

\item[(6)] The \method{sort()} and \method{reverse()} methods modify the
\item[(7)] The \method{sort()} and \method{reverse()} methods modify the
list in place for economy of space when sorting or reversing a large
list. To remind you that they operate by side effect, they don't return
the sorted or reversed list.

\item[(7)] The \method{sort()} method takes an optional argument
\item[(8)] The \method{sort()} method takes an optional argument
specifying a comparison function of two arguments (list items) which
should return a negative, zero or positive number depending on whether
the first argument is considered smaller than, equal to, or larger
Expand Down
7 changes: 7 additions & 0 deletions Doc/ref/ref3.tex
Expand Up @@ -252,6 +252,13 @@ \section{The standard type hierarchy\label{types}}
renumbered so that it starts at 0.
\index{slicing}

Some sequences also support ``extended slicing'' with a third ``step''
parameter: \code{\var{a}[\var{i}:\var{j}:\var{k}]} selects all items
of \var{a} with index \var{x} where \code{\var{x} = \var{i} +
\var{n}*\var{k}}, \var{n} \code{>=} \code{0} and \var{i} \code{<=}
\var{x} \code{<} \var{j}.
\index{extended slicing}

Sequences are distinguished according to their mutability:

\begin{description}
Expand Down
9 changes: 9 additions & 0 deletions Doc/whatsnew/whatsnew23.tex
Expand Up @@ -336,6 +336,15 @@ \section{PEP 285: The \class{bool} Type\label{section-bool}}

\end{seealso}

\section{Extended Slices\label{extended-slices}}

Ever since Python 1.4 the slice syntax has supported a third
``stride'' argument, but the builtin sequence types have not supported
this feature (it was initially included at the behest of the
developers of the Numerical Python package). This changes with Python
2.3.

% XXX examples, etc.

%======================================================================
%\section{Other Language Changes}
Expand Down
3 changes: 3 additions & 0 deletions Include/sliceobject.h
Expand Up @@ -32,6 +32,9 @@ DL_IMPORT(PyObject *) PySlice_New(PyObject* start, PyObject* stop,
PyObject* step);
DL_IMPORT(int) PySlice_GetIndices(PySliceObject *r, int length,
int *start, int *stop, int *step);
DL_IMPORT(int) PySlice_GetIndicesEx(PySliceObject *r, int length,
int *start, int *stop,
int *step, int *slicelength);

#ifdef __cplusplus
}
Expand Down
2 changes: 1 addition & 1 deletion Lib/test/test_bool.py
Expand Up @@ -219,7 +219,7 @@ class C(bool):
veris(operator.isSequenceType([]), True)
veris(operator.contains([], 1), False)
veris(operator.contains([1], 1), True)
veris(operator.isMappingType([]), False)
veris(operator.isMappingType(1), False)
veris(operator.isMappingType({}), True)
veris(operator.lt(0, 0), False)
veris(operator.lt(0, 1), True)
Expand Down
72 changes: 72 additions & 0 deletions Lib/test/test_types.py
Expand Up @@ -188,6 +188,31 @@ class C: pass
x = 'x'*103
if '%s!'%x != x+'!': raise TestFailed, 'nasty string formatting bug'

#extended slices for strings
a = '0123456789'
vereq(a[::], a)
vereq(a[::2], '02468')
vereq(a[1::2], '13579')
vereq(a[::-1],'9876543210')
vereq(a[::-2], '97531')
vereq(a[3::-2], '31')
vereq(a[-100:100:], a)
vereq(a[100:-100:-1], a[::-1])
vereq(a[-100L:100L:2L], '02468')

if have_unicode:
a = unicode('0123456789', 'ascii')
vereq(a[::], a)
vereq(a[::2], unicode('02468', 'ascii'))
vereq(a[1::2], unicode('13579', 'ascii'))
vereq(a[::-1], unicode('9876543210', 'ascii'))
vereq(a[::-2], unicode('97531', 'ascii'))
vereq(a[3::-2], unicode('31', 'ascii'))
vereq(a[-100:100:], a)
vereq(a[100:-100:-1], a[::-1])
vereq(a[-100L:100L:2L], unicode('02468', 'ascii'))


print '6.5.2 Tuples'
if len(()) != 0: raise TestFailed, 'len(())'
if len((1,)) != 1: raise TestFailed, 'len((1,))'
Expand All @@ -207,6 +232,19 @@ class C: pass
x += (1,)
if x != (1,): raise TestFailed, 'tuple resize from () failed'

# extended slicing - subscript only for tuples
a = (0,1,2,3,4)
vereq(a[::], a)
vereq(a[::2], (0,2,4))
vereq(a[1::2], (1,3))
vereq(a[::-1], (4,3,2,1,0))
vereq(a[::-2], (4,2,0))
vereq(a[3::-2], (3,1))
vereq(a[-100:100:], a)
vereq(a[100:-100:-1], a[::-1])
vereq(a[-100L:100L:2L], (0,2,4))


print '6.5.3 Lists'
if len([]) != 0: raise TestFailed, 'len([])'
if len([1,]) != 1: raise TestFailed, 'len([1,])'
Expand Down Expand Up @@ -322,6 +360,40 @@ def myComparison(x,y):
if a[ 3: pow(2,145L) ] != [3,4]:
raise TestFailed, "list slicing with too-large long integer"


# extended slicing

# subscript
a = [0,1,2,3,4]
vereq(a[::], a)
vereq(a[::2], [0,2,4])
vereq(a[1::2], [1,3])
vereq(a[::-1], [4,3,2,1,0])
vereq(a[::-2], [4,2,0])
vereq(a[3::-2], [3,1])
vereq(a[-100:100:], a)
vereq(a[100:-100:-1], a[::-1])
vereq(a[-100L:100L:2L], [0,2,4])
# deletion
del a[::2]
vereq(a, [1,3])
a = range(5)
del a[1::2]
vereq(a, [0,2,4])
a = range(5)
del a[1::-2]
vereq(a, [0,2,3,4])
# assignment
a = range(10)
a[::2] = [-1]*5
vereq(a, [-1, 1, -1, 3, -1, 5, -1, 7, -1, 9])
a = range(10)
a[::-4] = [10]*3
vereq(a, [0, 10, 2, 3, 4, 10, 6, 7, 8 ,10])
a = range(4)
a[::-1] = a
vereq(a, [3, 2, 1, 0])

print '6.6 Mappings == Dictionaries'
d = {}
if d.keys() != []: raise TestFailed, '{}.keys()'
Expand Down
4 changes: 4 additions & 0 deletions Misc/NEWS
Expand Up @@ -6,6 +6,10 @@ Type/class unification and new-style classes

Core and builtins

- Most builtin sequences now support "extended slices", i.e. slices
with a third "stride" parameter. For example, "range(10)[1:6:2]"
evaluates to [1, 3, 5].

- Cycles going through the __class__ link of a new-style instance are
now detected by the garbage collector.

Expand Down

0 comments on commit 5efaf7e

Please sign in to comment.