Patch #552433: Special-case tuples. Avoid sub-type checking for lists.
Avoid checks for negative indices and duplicate checks for support of
the sequence protocol.
diff --git a/Doc/api/abstract.tex b/Doc/api/abstract.tex
index 0e25afa..e4f299d 100644
--- a/Doc/api/abstract.tex
+++ b/Doc/api/abstract.tex
@@ -765,6 +765,13 @@
   and that \var{i} is within bounds.
 \end{cfuncdesc}
 
+\begin{cfuncdesc}{PyObject*}{PySequence_ITEM}{PyObject *o, int i}
+  Return the \var{i}th element of \var{o} or \NULL on failure.
+  Macro form of \cfunction{PySequence_GetItem()} but without checking
+  that \cfunction{PySequence_Check(\var{o})} is true and without
+  adjustment for negative indices.  
+\end{cfuncdesc}
+
 \begin{cfuncdesc}{int}{PySequence_Fast_GET_SIZE}{PyObject *o}
   Returns the length of \var{o}, assuming that \var{o} was
   returned by \cfunction{PySequence_Fast()} and that \var{o} is
diff --git a/Include/abstract.h b/Include/abstract.h
index 226e5e8..459bd56 100644
--- a/Include/abstract.h
+++ b/Include/abstract.h
@@ -1015,6 +1015,12 @@
          PySequence_Fast, and that i is within bounds.
        */
 
+#define PySequence_ITEM(o, i)\
+	( o->ob_type->tp_as_sequence->sq_item(o, i) )
+       /* Assume tp_as_sequence and sq_item exist and that i does not
+	  need to be corrected for a negative index
+       */     
+
      DL_IMPORT(int) PySequence_Count(PyObject *o, PyObject *value);
 
        /*
diff --git a/Misc/NEWS b/Misc/NEWS
index 34befe8..d31e09d 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -192,6 +192,10 @@
 
 C API
 
+- Added new macro PySequence_ITEM(o, i) that directly calls
+  sq_item without rechecking that o is a sequence and without
+  adjusting for negative indices.
+
 - PyRange_New() now raises ValueError if the fourth argument is not 1.
   This is part of the removal of deprecated features of the xrange
   object.
diff --git a/Objects/iterobject.c b/Objects/iterobject.c
index 789eb6c..de9f2f9 100644
--- a/Objects/iterobject.c
+++ b/Objects/iterobject.c
@@ -12,6 +12,11 @@
 PySeqIter_New(PyObject *seq)
 {
 	seqiterobject *it;
+
+	if (!PySequence_Check(seq)) {
+		PyErr_BadInternalCall();
+		return NULL;
+	}	
 	it = PyObject_GC_New(seqiterobject, &PySeqIter_Type);
 	if (it == NULL)
 		return NULL;
@@ -63,7 +68,7 @@
 	it = (seqiterobject *)iterator;
 	seq = it->it_seq;
 
-	if (PyList_Check(seq)) {
+	if (PyList_CheckExact(seq)) {
 		PyObject *item;
 		if (it->it_index >= PyList_GET_SIZE(seq)) {
 			return NULL;
@@ -73,8 +78,19 @@
 		Py_INCREF(item);
 		return item;
 	}
+	if (PyTuple_CheckExact(seq)) {
+		PyObject *item;
+		if (it->it_index >= PyTuple_GET_SIZE(seq)) {
+			return NULL;
+		}
+		item = PyTuple_GET_ITEM(seq, it->it_index);
+		it->it_index++;
+		Py_INCREF(item);
+		return item;
+	}
 	else {
-		PyObject *result = PySequence_GetItem(seq, it->it_index++);
+		PyObject *result = PySequence_ITEM(seq, it->it_index);
+		it->it_index++;
 		if (result != NULL) {
 			return result;
 		}