[Python-checkins] r51297 - peps/trunk/pep-0357.txt

neal.norwitz python-checkins at python.org
Tue Aug 15 08:27:33 CEST 2006


Author: neal.norwitz
Date: Tue Aug 15 08:27:32 2006
New Revision: 51297

Modified:
   peps/trunk/pep-0357.txt
Log:
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.


Modified: peps/trunk/pep-0357.txt
==============================================================================
--- peps/trunk/pep-0357.txt	(original)
+++ peps/trunk/pep-0357.txt	Tue Aug 15 08:27:32 2006
@@ -45,31 +45,68 @@
 Proposal
  
     Add an nb_index slot to PyNumberMethods, and a corresponding
-    __index__ special method.  Objects could define a function to place
-    in the nb_index slot that returns an appropriate C-integer (Py_ssize_t
-    after PEP 353).  This C-integer will be used whenever Python needs
-    one such as in PySequence_GetSlice, PySequence_SetSlice, and
-    PySequence_DelSlice.  
+    __index__ special method.  Objects could define a function to
+    place in the nb_index slot that returns a Python integer
+    (either an int or a long). This integer can 
+    then be appropriately converted to a Py_ssize_t value whenever 
+    Python needs one such as in PySequence_GetSlice, 
+    PySequence_SetSlice, and PySequence_DelSlice.
 
 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
 
        def __index__(self):
            return obj
        
-       where obj must be either an int or a long. 
+       where obj must be either an int or a long.
+
+    3) 3 new abstract C-API functions will be added 
 
-    3) A new C-API function PyNumber_Index will be added with signature
+       a) The first checks to see if the object supports the index
+          slot and if it is filled in. 
 
-       Py_ssize_t PyNumber_Index (PyObject *obj)
+          int PyIndex_Check(obj)
 
-       which will return obj->ob_type->tp_as_number->nb_index(obj) if it is available. 
-       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
        equivalent of obj.__index__() and raises an error if obj does not implement
@@ -90,13 +127,19 @@
        slots for subscript access and use a special-check for integers to 
        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 
        Python Object that has the nb_index slot.  
 
     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
 
@@ -129,13 +172,22 @@
     for examples of names that were suggested such as "__discrete__" and 
     "__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
-    needed by the sequence interface.  In Python 2.5 this is
-    Py_ssize_t.  As this is the primary purpose of the slot, it
-    makes sense to return the C-integer directly and not wrapped
-    in a Python int object. 
+    Intially Py_ssize_t was selected as the return type for the
+    nb_index slot.  However, this led to an inability to track and
+    distinguish overflow and underflow errors without ugly and brittle
+    hacks. As the nb_index slot is used in at least 3 different ways 
+    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?
 


More information about the Python-checkins mailing list