Patch from /F:
this patch introduces PySequence_Fast and PySequence_Fast_GET_ITEM,
and modifies the list.extend method to accept any kind of sequence.
diff --git a/Include/abstract.h b/Include/abstract.h
index 12d799d..70c0e7c 100644
--- a/Include/abstract.h
+++ b/Include/abstract.h
@@ -731,7 +731,6 @@
        /*
 	 Return the ith element of o, or NULL on failure. This is the
 	 equivalent of the Python expression: o[i].
-
        */
 
      DL_IMPORT(PyObject *) PySequence_GetSlice Py_PROTO((PyObject *o, int i1, int i2));
@@ -783,6 +782,7 @@
 	 This is equivalent to the Python expression: tuple(o)
        */
 
+
      DL_IMPORT(PyObject *) PySequence_List Py_PROTO((PyObject *o));
 
        /*
@@ -790,6 +790,25 @@
 	 This is equivalent to the Python expression: list(o)
        */
 
+     DL_IMPORT(PyObject *) PySequence_Fast Py_PROTO((PyObject *o, const char* m));
+
+       /*
+         Returns the sequence, o, as a tuple, unless it's already a
+         tuple or list.  Use PySequence_Fast_GET_ITEM to access the
+         members of this list.
+
+         Returns NULL on failure.  If the object is not a sequence,
+         raises a TypeError exception with m as the message text.
+       */
+
+#define PySequence_Fast_GET_ITEM(o, i)\
+     (PyList_Check(o) ? PyList_GET_ITEM(o, i) : PyTuple_GET_ITEM(o, i))
+
+       /*
+	 Return the ith element of o, assuming that o was returned by
+         PySequence_Fast, and that i is within bounds.
+       */
+
      DL_IMPORT(int) PySequence_Count Py_PROTO((PyObject *o, PyObject *value));
 
        /*
diff --git a/Objects/abstract.c b/Objects/abstract.c
index 410b80b..79af2f8 100644
--- a/Objects/abstract.c
+++ b/Objects/abstract.c
@@ -1207,6 +1207,26 @@
 	return type_error("list() argument must be a sequence");
 }
 
+PyObject *
+PySequence_Fast(v, m)
+	PyObject *v;
+	const char* m;
+{
+	if (v == NULL)
+		return null_error();
+
+	if (PyList_Check(v) || PyTuple_Check(v)) {
+		Py_INCREF(v);
+		return v;
+	}
+
+	v = PySequence_Tuple(v);
+	if (v == NULL && PyErr_ExceptionMatches(PyExc_TypeError))
+		return type_error(m);
+
+	return v;
+}
+
 int
 PySequence_Count(s, o)
 	PyObject *s;
diff --git a/Objects/listobject.c b/Objects/listobject.c
index 3bb5aec..163ba2a 100644
--- a/Objects/listobject.c
+++ b/Objects/listobject.c
@@ -627,16 +627,14 @@
 	if (!PyArg_ParseTuple(args, "O:extend", &b))
 		return NULL;
 
-	if (!PyList_Check(b)) {
-		PyErr_SetString(PyExc_TypeError,
-				"list.extend() argument must be a list");
+	b = PySequence_Fast(b, "list.extend() argument must be a sequence");
+	if (!b)
 		return NULL;
-	}
-	if (PyList_GET_SIZE(b) == 0) {
+
+	if (PyObject_Length(b) == 0)
 		/* short circuit when b is empty */
-		Py_INCREF(Py_None);
-		return Py_None;
-	}
+		goto ok;
+
 	if (self == (PyListObject*)b) {
 		/* as in list_ass_slice() we must special case the
 		 * situation: a.extend(a)
@@ -644,6 +642,7 @@
 		 * XXX: I think this way ought to be faster than using
 		 * list_slice() the way list_ass_slice() does.
 		 */
+		Py_DECREF(b);
 		b = PyList_New(selflen);
 		if (!b)
 			return NULL;
@@ -653,33 +652,29 @@
 			PyList_SET_ITEM(b, i, o);
 		}
 	}
-	else
-		/* we want b to have the same refcount semantics for the
-		 * Py_XDECREF() in the finally clause regardless of which
-		 * branch in the above conditional we took.
-		 */
-		Py_INCREF(b);
 
-	blen = PyList_GET_SIZE(b);
+	blen = PyObject_Length(b);
+
 	/* resize a using idiom */
 	items = self->ob_item;
 	NRESIZE(items, PyObject*, selflen + blen);
-	if (items == NULL ) {
+	if (items == NULL) {
 		PyErr_NoMemory();
-		goto finally;
+		goto failed;
 	}
 	self->ob_item = items;
 
-	/* populate the end self with b's items */
+	/* populate the end of self with b's items */
 	for (i = 0; i < blen; i++) {
-		PyObject *o = PyList_GET_ITEM(b, i);
+		PyObject *o = PySequence_Fast_GET_ITEM(b, i);
 		Py_INCREF(o);
 		PyList_SET_ITEM(self, self->ob_size++, o);
 	}
+  ok:
 	res = Py_None;
 	Py_INCREF(res);
-  finally:
-	Py_XDECREF(b);
+  failed:
+	Py_DECREF(b);
 	return res;
 }