Skip to content

Commit 297d31f

Browse files
author
guido.van.rossum
committed
Checking in the code for PEP 357.
This was mostly written by Travis Oliphant. I've inspected it all; Neal Norwitz and MvL have also looked at it (in an earlier incarnation). git-svn-id: http://svn.python.org/projects/python/trunk@42899 6015fed2-1504-0410-9fe1-9d1591cc4771
1 parent 1fb3f82 commit 297d31f

19 files changed

Lines changed: 269 additions & 150 deletions

Doc/api/abstract.tex

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -346,6 +346,7 @@ \section{Object Protocol \label{object}}
346346
either the sequence and mapping protocols, the sequence length is
347347
returned. On error, \code{-1} is returned. This is the equivalent
348348
to the Python expression \samp{len(\var{o})}.\bifuncindex{len}
349+
\versionadded{2.5}
349350
\end{cfuncdesc}
350351

351352

@@ -689,6 +690,10 @@ \section{Number Protocol \label{number}}
689690
\samp{float(\var{o})}.\bifuncindex{float}
690691
\end{cfuncdesc}
691692

693+
\begin{cfuncdesc}{Py_ssize_t}{PyNumber_Index}{PyObject *o}
694+
Returns the \var{o} converted to a Py_ssize_t integer on success, or
695+
-1 with an exception raised on failure.
696+
\end{cfuncdesc}
692697

693698
\section{Sequence Protocol \label{sequence}}
694699

Doc/lib/liboperator.tex

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,11 @@ \section{\module{operator} ---
171171
Return the bitwise exclusive or of \var{a} and \var{b}.
172172
\end{funcdesc}
173173

174+
\begin{funcdesc}{index}{a}
175+
\funcline{__index__}{a}
176+
Return \var{a} converted to an integer. Equivalent to \var{a}\code{.__index__()}.
177+
\versionadded{2.5}
178+
\end{funcdesc}
174179

175180
Operations which work with sequences include:
176181

Doc/ref/ref3.tex

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1978,6 +1978,13 @@ \subsection{Emulating numeric types\label{numeric-types}}
19781978
\function{hex()}\bifuncindex{hex}. Should return a string value.
19791979
\end{methoddesc}
19801980

1981+
\begin{methoddesc}[numeric object]{__index__}{self}
1982+
Called to implement operator.index(). Also called whenever Python
1983+
needs an integer object (such as in slicing). Must return an integer
1984+
(int or long).
1985+
\versionadded{2.5}
1986+
\end{methoddesc}
1987+
19811988
\begin{methoddesc}[numeric object]{__coerce__}{self, other}
19821989
Called to implement ``mixed-mode'' numeric arithmetic. Should either
19831990
return a 2-tuple containing \var{self} and \var{other} converted to

Include/abstract.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -748,6 +748,14 @@ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx*/
748748
749749
*/
750750

751+
PyAPI_FUNC(Py_ssize_t) PyNumber_Index(PyObject *);
752+
753+
/*
754+
Returns the object converted to Py_ssize_t on success
755+
or -1 with an error raised on failure.
756+
*/
757+
758+
751759
PyAPI_FUNC(PyObject *) PyNumber_Int(PyObject *o);
752760

753761
/*

Include/object.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,9 @@ typedef struct {
206206
binaryfunc nb_true_divide;
207207
binaryfunc nb_inplace_floor_divide;
208208
binaryfunc nb_inplace_true_divide;
209+
210+
/* Added in release 2.5 */
211+
lenfunc nb_index;
209212
} PyNumberMethods;
210213

211214
typedef struct {
@@ -503,13 +506,16 @@ given type object has a specified feature.
503506
/* Objects support garbage collection (see objimp.h) */
504507
#define Py_TPFLAGS_HAVE_GC (1L<<14)
505508

506-
/* These two bits are preserved for Stackless Python, next after this is 16 */
509+
/* These two bits are preserved for Stackless Python, next after this is 17 */
507510
#ifdef STACKLESS
508511
#define Py_TPFLAGS_HAVE_STACKLESS_EXTENSION (3L<<15)
509512
#else
510513
#define Py_TPFLAGS_HAVE_STACKLESS_EXTENSION 0
511514
#endif
512515

516+
/* Objects support nb_index in PyNumberMethods */
517+
#define Py_TPFLAGS_HAVE_INDEX (1L<<17)
518+
513519
#define Py_TPFLAGS_DEFAULT ( \
514520
Py_TPFLAGS_HAVE_GETCHARBUFFER | \
515521
Py_TPFLAGS_HAVE_SEQUENCE_IN | \
@@ -519,6 +525,7 @@ given type object has a specified feature.
519525
Py_TPFLAGS_HAVE_ITER | \
520526
Py_TPFLAGS_HAVE_CLASS | \
521527
Py_TPFLAGS_HAVE_STACKLESS_EXTENSION | \
528+
Py_TPFLAGS_HAVE_INDEX | \
522529
0)
523530

524531
#define PyType_HasFeature(t,f) (((t)->tp_flags & (f)) != 0)

Lib/test/test_index.py

Whitespace-only changes.

Modules/arraymodule.c

Lines changed: 11 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1569,19 +1569,17 @@ array_repr(arrayobject *a)
15691569
return s;
15701570
}
15711571

1572+
#define HASINDEX(o) PyType_HasFeature((o)->ob_type, Py_TPFLAGS_HAVE_INDEX)
1573+
15721574
static PyObject*
15731575
array_subscr(arrayobject* self, PyObject* item)
15741576
{
1575-
if (PyInt_Check(item)) {
1576-
Py_ssize_t i = PyInt_AS_LONG(item);
1577-
if (i < 0)
1578-
i += self->ob_size;
1579-
return array_item(self, i);
1580-
}
1581-
else if (PyLong_Check(item)) {
1582-
Py_ssize_t i = PyInt_AsSsize_t(item);
1583-
if (i == -1 && PyErr_Occurred())
1577+
PyNumberMethods *nb = item->ob_type->tp_as_number;
1578+
if (nb != NULL && HASINDEX(item) && nb->nb_index != NULL) {
1579+
Py_ssize_t i = nb->nb_index(item);
1580+
if (i==-1 && PyErr_Occurred()) {
15841581
return NULL;
1582+
}
15851583
if (i < 0)
15861584
i += self->ob_size;
15871585
return array_item(self, i);
@@ -1626,15 +1624,10 @@ array_subscr(arrayobject* self, PyObject* item)
16261624
static int
16271625
array_ass_subscr(arrayobject* self, PyObject* item, PyObject* value)
16281626
{
1629-
if (PyInt_Check(item)) {
1630-
Py_ssize_t i = PyInt_AS_LONG(item);
1631-
if (i < 0)
1632-
i += self->ob_size;
1633-
return array_ass_item(self, i, value);
1634-
}
1635-
else if (PyLong_Check(item)) {
1636-
Py_ssize_t i = PyInt_AsSsize_t(item);
1637-
if (i == -1 && PyErr_Occurred())
1627+
PyNumberMethods *nb = item->ob_type->tp_as_number;
1628+
if (nb != NULL && HASINDEX(item) && nb->nb_index != NULL) {
1629+
Py_ssize_t i = nb->nb_index(item);
1630+
if (i==-1 && PyErr_Occurred())
16381631
return -1;
16391632
if (i < 0)
16401633
i += self->ob_size;

Modules/mmapmodule.c

Lines changed: 8 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -815,33 +815,24 @@ static PyTypeObject mmap_object_type = {
815815
};
816816

817817

818+
#define HASINDEX(o) PyType_HasFeature((o)->ob_type, Py_TPFLAGS_HAVE_INDEX)
819+
818820
/* extract the map size from the given PyObject
819821
820822
Returns -1 on error, with an appropriate Python exception raised. On
821823
success, the map size is returned. */
822824
static Py_ssize_t
823825
_GetMapSize(PyObject *o)
824826
{
825-
if (PyInt_Check(o)) {
826-
long i = PyInt_AsLong(o);
827-
if (PyErr_Occurred())
827+
PyNumberMethods *nb = o->ob_type->tp_as_number;
828+
if (nb != NULL && HASINDEX(o) && nb->nb_index != NULL) {
829+
Py_ssize_t i = nb->nb_index(o);
830+
if (i==-1 && PyErr_Occurred())
828831
return -1;
829832
if (i < 0)
830833
goto onnegoverflow;
831-
return i;
832-
}
833-
else if (PyLong_Check(o)) {
834-
Py_ssize_t i = PyInt_AsSsize_t(o);
835-
if (PyErr_Occurred()) {
836-
/* yes negative overflow is mistaken for positive overflow
837-
but not worth the trouble to check sign of 'i' */
838-
if (PyErr_ExceptionMatches(PyExc_OverflowError))
839-
goto onposoverflow;
840-
else
841-
return -1;
842-
}
843-
if (i < 0)
844-
goto onnegoverflow;
834+
if (i==PY_SSIZE_T_MAX)
835+
goto onposoverflow;
845836
return i;
846837
}
847838
else {

Modules/operator.c

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,20 @@ op_ipow(PyObject *s, PyObject *a)
130130
return NULL;
131131
}
132132

133+
static PyObject *
134+
op_index(PyObject *s, PyObject *a)
135+
{
136+
Py_ssize_t i;
137+
PyObject *a1;
138+
if (!PyArg_UnpackTuple(a,"index", 1, 1, &a1))
139+
return NULL;
140+
i = PyNumber_Index(a1);
141+
if (i == -1 && PyErr_Occurred())
142+
return NULL;
143+
else
144+
return PyInt_FromSsize_t(i);
145+
}
146+
133147
static PyObject*
134148
is_(PyObject *s, PyObject *a)
135149
{
@@ -229,6 +243,7 @@ spam1o(isMappingType,
229243

230244
spam1(is_, "is_(a, b) -- Same as a is b.")
231245
spam1(is_not, "is_not(a, b) -- Same as a is not b.")
246+
spam2(index, __index__, "index(a) -- Same as a.__index__()")
232247
spam2(add,__add__, "add(a, b) -- Same as a + b.")
233248
spam2(sub,__sub__, "sub(a, b) -- Same as a - b.")
234249
spam2(mul,__mul__, "mul(a, b) -- Same as a * b.")

Objects/abstract.c

Lines changed: 32 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
#define NEW_STYLE_NUMBER(o) PyType_HasFeature((o)->ob_type, \
99
Py_TPFLAGS_CHECKTYPES)
1010

11+
#define HASINDEX(o) PyType_HasFeature((o)->ob_type, Py_TPFLAGS_HAVE_INDEX)
12+
1113
/* Shorthands to return certain errors */
1214

1315
static PyObject *
@@ -119,10 +121,9 @@ PyObject_GetItem(PyObject *o, PyObject *key)
119121
return m->mp_subscript(o, key);
120122

121123
if (o->ob_type->tp_as_sequence) {
122-
if (PyInt_Check(key))
123-
return PySequence_GetItem(o, PyInt_AsLong(key));
124-
else if (PyLong_Check(key)) {
125-
long key_value = PyLong_AsLong(key);
124+
PyNumberMethods *nb = key->ob_type->tp_as_number;
125+
if (nb != NULL && HASINDEX(key) && nb->nb_index != NULL) {
126+
Py_ssize_t key_value = nb->nb_index(key);
126127
if (key_value == -1 && PyErr_Occurred())
127128
return NULL;
128129
return PySequence_GetItem(o, key_value);
@@ -148,10 +149,9 @@ PyObject_SetItem(PyObject *o, PyObject *key, PyObject *value)
148149
return m->mp_ass_subscript(o, key, value);
149150

150151
if (o->ob_type->tp_as_sequence) {
151-
if (PyInt_Check(key))
152-
return PySequence_SetItem(o, PyInt_AsLong(key), value);
153-
else if (PyLong_Check(key)) {
154-
long key_value = PyLong_AsLong(key);
152+
PyNumberMethods *nb = key->ob_type->tp_as_number;
153+
if (nb != NULL && HASINDEX(key) && nb->nb_index != NULL) {
154+
Py_ssize_t key_value = nb->nb_index(key);
155155
if (key_value == -1 && PyErr_Occurred())
156156
return -1;
157157
return PySequence_SetItem(o, key_value, value);
@@ -180,10 +180,9 @@ PyObject_DelItem(PyObject *o, PyObject *key)
180180
return m->mp_ass_subscript(o, key, (PyObject*)NULL);
181181

182182
if (o->ob_type->tp_as_sequence) {
183-
if (PyInt_Check(key))
184-
return PySequence_DelItem(o, PyInt_AsLong(key));
185-
else if (PyLong_Check(key)) {
186-
long key_value = PyLong_AsLong(key);
183+
PyNumberMethods *nb = key->ob_type->tp_as_number;
184+
if (nb != NULL && HASINDEX(key) && nb->nb_index != NULL) {
185+
Py_ssize_t key_value = nb->nb_index(key);
187186
if (key_value == -1 && PyErr_Occurred())
188187
return -1;
189188
return PySequence_DelItem(o, key_value);
@@ -647,45 +646,18 @@ PyNumber_Add(PyObject *v, PyObject *w)
647646
static PyObject *
648647
sequence_repeat(ssizeargfunc repeatfunc, PyObject *seq, PyObject *n)
649648
{
650-
long count;
651-
if (PyInt_Check(n)) {
652-
count = PyInt_AsLong(n);
653-
}
654-
else if (PyLong_Check(n)) {
655-
count = PyLong_AsLong(n);
649+
Py_ssize_t count;
650+
PyNumberMethods *nb = n->ob_type->tp_as_number;
651+
if (nb != NULL && HASINDEX(n) && nb->nb_index != NULL) {
652+
count = nb->nb_index(n);
656653
if (count == -1 && PyErr_Occurred())
657654
return NULL;
658655
}
659656
else {
660657
return type_error(
661658
"can't multiply sequence by non-int");
662659
}
663-
#if LONG_MAX != INT_MAX
664-
if (count > INT_MAX) {
665-
PyErr_SetString(PyExc_ValueError,
666-
"sequence repeat count too large");
667-
return NULL;
668-
}
669-
else if (count < INT_MIN)
670-
count = INT_MIN;
671-
/* XXX Why don't I either
672-
673-
- set count to -1 whenever it's negative (after all,
674-
sequence repeat usually treats negative numbers
675-
as zero(); or
676-
677-
- raise an exception when it's less than INT_MIN?
678-
679-
I'm thinking about a hypothetical use case where some
680-
sequence type might use a negative value as a flag of
681-
some kind. In those cases I don't want to break the
682-
code by mapping all negative values to -1. But I also
683-
don't want to break e.g. []*(-sys.maxint), which is
684-
perfectly safe, returning []. As a compromise, I do
685-
map out-of-range negative values.
686-
*/
687-
#endif
688-
return (*repeatfunc)(seq, (int)count);
660+
return (*repeatfunc)(seq, count);
689661
}
690662

691663
PyObject *
@@ -960,6 +932,22 @@ int_from_string(const char *s, Py_ssize_t len)
960932
return x;
961933
}
962934

935+
/* Return a Py_ssize_t integer from the object item */
936+
Py_ssize_t
937+
PyNumber_Index(PyObject *item)
938+
{
939+
Py_ssize_t value = -1;
940+
PyNumberMethods *nb = item->ob_type->tp_as_number;
941+
if (nb != NULL && HASINDEX(item) && nb->nb_index != NULL) {
942+
value = nb->nb_index(item);
943+
}
944+
else {
945+
PyErr_SetString(PyExc_IndexError,
946+
"object cannot be interpreted as an index");
947+
}
948+
return value;
949+
}
950+
963951
PyObject *
964952
PyNumber_Int(PyObject *o)
965953
{

0 commit comments

Comments
 (0)