Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 38fff8c

Browse files
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).
1 parent 9d78550 commit 38fff8c

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)