Movatterモバイル変換


[0]ホーム

URL:


Following system colour schemeSelected dark colour schemeSelected light colour scheme

Python Enhancement Proposals

PEP 357 – Allowing Any Object to be Used for Slicing

PEP 357 – Allowing Any Object to be Used for Slicing

Author:
Travis Oliphant <oliphant at ee.byu.edu>
Status:
Final
Type:
Standards Track
Created:
09-Feb-2006
Python-Version:
2.5
Post-History:


Table of Contents

Abstract

This PEP proposes adding annb_index slot inPyNumberMethods and an__index__ special method so that arbitrary objects can be usedwhenever integers are explicitly needed in Python, such as in slicesyntax (from which the slot gets its name).

Rationale

Currently integers and long integers play a special role inslicing in that they are the only objects allowed in slicesyntax. In other words, if X is an object implementing thesequence protocol, thenX[obj1:obj2] is only valid ifobj1 andobj2 are both integers or long integers. There is no way forobj1andobj2 to tell Python that they could be reasonably used asindexes into a sequence. This is an unnecessary limitation.

In NumPy, for example, there are 8 different integer scalarscorresponding to unsigned and signed integers of 8, 16, 32, and 64bits. These type-objects could reasonably be used as integers inmany places where Python expects true integers but cannot inherit fromthe Python integer type because of incompatible memory layouts.There should be some way to be able to tell Python that an object canbehave like an integer.

It is not possible to use thenb_int (and__int__ special method)for this purpose because that method is used tocoerce objectsto integers. It would be inappropriate to allow every object thatcan be coerced to an integer to be used as an integer everywherePython expects a true integer. For example, if__int__ were usedto convert an object to an integer in slicing, then float objectswould be allowed in slicing andx[3.2:5.8] would not raise an erroras it should.

Proposal

Add annb_index slot toPyNumberMethods, and a corresponding__index__ special method. Objects could define a function toplace in thenb_index slot that returns a Python integer(either an int or a long). This integer canthen be appropriately converted to aPy_ssize_t value wheneverPython needs one such as inPySequence_GetSlice,PySequence_SetSlice, andPySequence_DelSlice.

Specification

  1. Thenb_index slot will have the following signature:
    PyObject*index_func(PyObject*self)

    The returned object must be a PythonIntType orPythonLongType. NULL should be returned onerror with an appropriate error set.

  2. The__index__ special method will have the signature:
    def__index__(self):returnobj

    where obj must be either an int or a long.

  3. 3 new abstract C-API functions will be added
    1. The first checks to see if the object supports the indexslot and if it is filled in.
      intPyIndex_Check(obj)

      This will return true if the object defines thenb_indexslot.

    2. The second is a simple wrapper around thenb_index call thatraisesPyExc_TypeError if the call is not available or if itdoesn’t return an int or long. Because thePyIndex_Check is performed inside thePyNumber_Index callyou can call it directly and manage any error rather thancheck for compatibility first.
      PyObject*PyNumber_Index(PyObject*obj)
    3. The third call helps deal with the common situation ofactually needing aPy_ssize_t value from the object to use forindexing or other needs.
      Py_ssize_tPyNumber_AsSsize_t(PyObject*obj,PyObject*exc)

      The function calls thenb_index slot of obj if it isavailable and then converts the returned Python integer intoaPy_ssize_t value. If this goes well, then the value isreturned. The second argument allows control over whathappens if the integer returned fromnb_index cannot fitinto aPy_ssize_t value.

      If exc is NULL, then the returned value will be clipped toPY_SSIZE_T_MAX orPY_SSIZE_T_MIN depending on whether thenb_index slot of obj returned a positive or negativeinteger. If exc is non-NULL, then it is the error objectthat will be set to replace thePyExc_OverflowError that wasraised when the Python integer or long was converted toPy_ssize_t.

  4. A newoperator.index(obj) function will be added that callsequivalent ofobj.__index__() and raises an error if obj does not implementthe special method.

Implementation Plan

  1. Add thenb_index slot inobject.h and modifytypeobject.c tocreate the__index__ method
  2. Change theISINT macro inceval.c toISINDEX and alter it toaccommodate objects with the index slot defined.
  3. Change the_PyEval_SliceIndex function to accommodate objectswith the index slot defined.
  4. Change all builtin objects (e.g. lists) that use theas_mappingslots for subscript access and use a special-check for integers tocheck for the slot as well.
  5. Add thenb_index slot to integers and long_integers(which just return themselves)
  6. AddPyNumber_Index C-API to return an integer from anyPython Object that has thenb_index slot.
  7. Add theoperator.index(x) function.
  8. Alterarrayobject.c andmmapmodule.c to use the new C-API for theirsub-scripting and other needs.
  9. Add unit-tests

Discussion Questions

Speed

Implementation should not slow down Python because integers and longintegers used as indexes will complete in the same number ofinstructions. The only change will be that what used to generatean error will now be acceptable.

Why not usenb_int which is already there?

Thenb_int method is used for coercion and so means somethingfundamentally different than what is requested here. This PEPproposes a method for something thatcan already be thought of asan integer communicate that information to Python when it needs aninteger. The biggest example of why usingnb_int would be a badthing is that float objects already define thenb_int method, butfloat objectsshould not be used as indexes in a sequence.

Why the name__index__?

Some questions were raised regarding the name__index__ when otherinterpretations of the slot are possible. For example, the slotcan be used any time Python requires an integer internally (suchas in"mystring"*3). The name was suggested by Guido becauseslicing syntax is the biggest reason for having such a slot andin the end no better name emerged. See the discussion thread[1]for examples of names that were suggested such as “__discrete__” and“__ordinal__”.

Why returnPyObject* fromnb_index?

InitiallyPy_ssize_t was selected as the return type for thenb_index slot. However, this led to an inability to track anddistinguish overflow and underflow errors without ugly and brittlehacks. As thenb_index slot is used in at least 3 different waysin 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 flexibilityneeded to handle all these cases. The importance of having thenecessary flexibility to handle all the use cases is critical.For example, the initial implementation that returnedPy_ssize_t fornb_index led to the discovery that on a 32-bit machine with >=2GB of RAMs='x'*(2**100) works butlen(s) was clipped at 2147483647.Several fixes were suggested but eventually it was decided thatnb_index needed to return a Python Object similar to thenb_intandnb_long slots in order to handle overflow correctly.

Why can’t__index__ return any object with thenb_index method?

This would allow infinite recursion in many different ways that are noteasy to check for. This restriction is similar to the requirement that__nonzero__ return an int or a bool.

Reference Implementation

Submitted as patch 1436368 to SourceForge.

References

[1]
Travis Oliphant, PEP for adding an sq_index slot so that any object, aor b, can be used in X[a:b] notation,

https://mail.python.org/pipermail/python-dev/2006-February/thread.html#60594

Copyright

This document is placed in the public domain.


Source:https://github.com/python/peps/blob/main/peps/pep-0357.rst

Last modified:2025-02-01 08:55:40 GMT


[8]ページ先頭

©2009-2026 Movatter.jp