Updates from Travis. I modified his version based on a followup mail that
stated: As long as the object returned is a proper sub-class then it should work fine. The Exact checks should be removed from both the code and the PEP.
This commit is contained in:
parent
8a3b0d11b7
commit
86fe83480d
88
pep-0357.txt
88
pep-0357.txt
|
@ -45,17 +45,22 @@ Rationale
|
||||||
Proposal
|
Proposal
|
||||||
|
|
||||||
Add an nb_index slot to PyNumberMethods, and a corresponding
|
Add an nb_index slot to PyNumberMethods, and a corresponding
|
||||||
__index__ special method. Objects could define a function to place
|
__index__ special method. Objects could define a function to
|
||||||
in the nb_index slot that returns an appropriate C-integer (Py_ssize_t
|
place in the nb_index slot that returns a Python integer
|
||||||
after PEP 353). This C-integer will be used whenever Python needs
|
(either an int or a long). This integer can
|
||||||
one such as in PySequence_GetSlice, PySequence_SetSlice, and
|
then be appropriately converted to a Py_ssize_t value whenever
|
||||||
PySequence_DelSlice.
|
Python needs one such as in PySequence_GetSlice,
|
||||||
|
PySequence_SetSlice, and PySequence_DelSlice.
|
||||||
|
|
||||||
Specification:
|
Specification:
|
||||||
|
|
||||||
1) The nb_index slot will have the signature
|
1) The nb_index slot will have the following signature
|
||||||
|
|
||||||
Py_ssize_t index_func (PyObject *self)
|
PyObject *index_func (PyObject *self)
|
||||||
|
|
||||||
|
The returned object must be a Python IntType or
|
||||||
|
Python LongType. NULL should be returned on
|
||||||
|
error with an appropriate error set.
|
||||||
|
|
||||||
2) The __index__ special method will have the signature
|
2) The __index__ special method will have the signature
|
||||||
|
|
||||||
|
@ -64,12 +69,44 @@ Specification:
|
||||||
|
|
||||||
where obj must be either an int or a long.
|
where obj must be either an int or a long.
|
||||||
|
|
||||||
3) A new C-API function PyNumber_Index will be added with signature
|
3) 3 new abstract C-API functions will be added
|
||||||
|
|
||||||
Py_ssize_t PyNumber_Index (PyObject *obj)
|
a) The first checks to see if the object supports the index
|
||||||
|
slot and if it is filled in.
|
||||||
|
|
||||||
which will return obj->ob_type->tp_as_number->nb_index(obj) if it is available.
|
int PyIndex_Check(obj)
|
||||||
A -1 will be returned and an exception set on an error.
|
|
||||||
|
This will return true if the object defines the nb_index
|
||||||
|
slot.
|
||||||
|
|
||||||
|
b) The second is a simple wrapper around the nb_index call that
|
||||||
|
raises PyExc_TypeError if the call is not available or if it
|
||||||
|
doesn't return an int or long. Because the
|
||||||
|
PyIndex_Check is performed inside the PyNumber_Index call
|
||||||
|
you can call it directly and manage any error rather than
|
||||||
|
check for compatibility first.
|
||||||
|
|
||||||
|
PyObject *PyNumber_Index (PyObject *obj)
|
||||||
|
|
||||||
|
c) The third call helps deal with the common situation of
|
||||||
|
actually needing a Py_ssize_t value from the object to use for
|
||||||
|
indexing or other needs.
|
||||||
|
|
||||||
|
Py_ssize_t PyNumber_AsSsize_t(PyObject *obj, PyObject *exc)
|
||||||
|
|
||||||
|
The function calls the nb_index slot of obj if it is
|
||||||
|
available and then converts the returned Python integer into
|
||||||
|
a Py_ssize_t value. If this goes well, then the value is
|
||||||
|
returned. The second argument allows control over what
|
||||||
|
happens if the integer returned from nb_index cannot fit
|
||||||
|
into a Py_ssize_t value.
|
||||||
|
|
||||||
|
If exc is NULL, then the returnd value will be clipped to
|
||||||
|
PY_SSIZE_T_MAX or PY_SSIZE_T_MIN depending on whether the
|
||||||
|
nb_index slot of obj returned a positive or negative
|
||||||
|
integer. If exc is non-NULL, then it is the error object
|
||||||
|
that will be set to replace the PyExc_OverflowError that was
|
||||||
|
raised when the Python integer or long was converted to Py_ssize_t.
|
||||||
|
|
||||||
4) A new operator.index(obj) function will be added that calls
|
4) A new operator.index(obj) function will be added that calls
|
||||||
equivalent of obj.__index__() and raises an error if obj does not implement
|
equivalent of obj.__index__() and raises an error if obj does not implement
|
||||||
|
@ -90,13 +127,19 @@ Implementation Plan
|
||||||
slots for subscript access and use a special-check for integers to
|
slots for subscript access and use a special-check for integers to
|
||||||
check for the slot as well.
|
check for the slot as well.
|
||||||
|
|
||||||
5) Add the nb_index slot to integers and long_integers.
|
5) Add the nb_index slot to integers and long_integers
|
||||||
|
(which just return themselves)
|
||||||
|
|
||||||
6) Add PyNumber_Index C-API to return an integer from any
|
6) Add PyNumber_Index C-API to return an integer from any
|
||||||
Python Object that has the nb_index slot.
|
Python Object that has the nb_index slot.
|
||||||
|
|
||||||
7) Add the operator.index(x) function.
|
7) Add the operator.index(x) function.
|
||||||
|
|
||||||
|
8) Alter arrayobject.c and mmapmodule.c to use the new C-API for their
|
||||||
|
sub-scripting and other needs.
|
||||||
|
|
||||||
|
9) Add unit-tests
|
||||||
|
|
||||||
|
|
||||||
Discussion Questions
|
Discussion Questions
|
||||||
|
|
||||||
|
@ -129,13 +172,22 @@ Discussion Questions
|
||||||
for examples of names that were suggested such as "__discrete__" and
|
for examples of names that were suggested such as "__discrete__" and
|
||||||
"__ordinal__".
|
"__ordinal__".
|
||||||
|
|
||||||
Why return Py_ssize_t from nb_index?
|
Why return PyObject * from nb_index?
|
||||||
|
|
||||||
The nb_index slot is primarily intended to return an integer
|
Intially Py_ssize_t was selected as the return type for the
|
||||||
needed by the sequence interface. In Python 2.5 this is
|
nb_index slot. However, this led to an inability to track and
|
||||||
Py_ssize_t. As this is the primary purpose of the slot, it
|
distinguish overflow and underflow errors without ugly and brittle
|
||||||
makes sense to return the C-integer directly and not wrapped
|
hacks. As the nb_index slot is used in at least 3 different ways
|
||||||
in a Python int object.
|
in the Python core (to get an integer, to get a slice end-point,
|
||||||
|
and to get a sequence index), there is quite a bit of flexibility
|
||||||
|
needed to handle all these cases. The importance of having the
|
||||||
|
necessary flexibility to handle all the use cases is critical.
|
||||||
|
For example, the initial implementation that returned Py_ssize_t for
|
||||||
|
nb_index led to the discovery that on a 32-bit machine with >=2GB of RAM
|
||||||
|
s = 'x' * (2**100) works but len(s) was clipped at 2147483647.
|
||||||
|
Several fixes were suggested but eventually it was decided that
|
||||||
|
nb_index needed to return a Python Object similar to the nb_int
|
||||||
|
and nb_long slots in order to handle overflow correctly.
|
||||||
|
|
||||||
Why can't __index__ return any object with the nb_index method?
|
Why can't __index__ return any object with the nb_index method?
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue