@@ -937,6 +937,7 @@ typedef struct {
937937 PyObject_HEAD
938938 Py_ssize_t nitems ;
939939 PyObject * item ;
940+ Py_ssize_t index ; // -1 unless *item* is a single non-negative integer index
940941} itemgetterobject ;
941942
942943static PyTypeObject itemgetter_type ;
@@ -948,6 +949,7 @@ itemgetter_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
948949 itemgetterobject * ig ;
949950 PyObject * item ;
950951 Py_ssize_t nitems ;
952+ Py_ssize_t index ;
951953
952954 if (!_PyArg_NoKeywords ("itemgetter" , kwds ))
953955 return NULL ;
@@ -967,6 +969,21 @@ itemgetter_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
967969 Py_INCREF (item );
968970 ig -> item = item ;
969971 ig -> nitems = nitems ;
972+ ig -> index = -1 ;
973+ if (PyLong_CheckExact (item )) {
974+ index = PyLong_AsSsize_t (item );
975+ if (index < 0 ) {
976+ /* If we get here, then either the index conversion failed
977+ * due to being out of range, or the index was a negative
978+ * integer. Either way, we clear any possible exception
979+ * and fall back to the slow path, where ig->index is -1.
980+ */
981+ PyErr_Clear ();
982+ }
983+ else {
984+ ig -> index = index ;
985+ }
986+ }
970987
971988 PyObject_GC_Track (ig );
972989 return (PyObject * )ig ;
@@ -993,12 +1010,27 @@ itemgetter_call(itemgetterobject *ig, PyObject *args, PyObject *kw)
9931010 PyObject * obj , * result ;
9941011 Py_ssize_t i , nitems = ig -> nitems ;
9951012
996- if (!_PyArg_NoKeywords ("itemgetter" , kw ))
997- return NULL ;
998- if (!PyArg_UnpackTuple (args , "itemgetter" , 1 , 1 , & obj ))
999- return NULL ;
1000- if (nitems == 1 )
1013+ assert (PyTuple_CheckExact (args ));
1014+ if (kw == NULL && PyTuple_GET_SIZE (args ) == 1 ) {
1015+ obj = PyTuple_GET_ITEM (args , 0 );
1016+ }
1017+ else {
1018+ if (!_PyArg_NoKeywords ("itemgetter" , kw ))
1019+ return NULL ;
1020+ if (!PyArg_UnpackTuple (args , "itemgetter" , 1 , 1 , & obj ))
1021+ return NULL ;
1022+ }
1023+ if (nitems == 1 ) {
1024+ if (ig -> index >= 0
1025+ && PyTuple_CheckExact (obj )
1026+ && ig -> index < PyTuple_GET_SIZE (obj ))
1027+ {
1028+ result = PyTuple_GET_ITEM (obj , ig -> index );
1029+ Py_INCREF (result );
1030+ return result ;
1031+ }
10011032 return PyObject_GetItem (obj , ig -> item );
1033+ }
10021034
10031035 assert (PyTuple_Check (ig -> item ));
10041036 assert (PyTuple_GET_SIZE (ig -> item ) == nitems );
0 commit comments