Generalize list(seq) to work with iterators.  This also generalizes list()
to no longer insist that len(seq) be defined.
NEEDS DOC CHANGES.
This is meant to be a model for how other functions of this ilk (max,
filter, etc) can be generalized similarly.  Feel encouraged to grab your
favorite and convert it!
Note some cute consequences:
    list(file) == file.readlines() == list(file.xreadlines())
    list(dict) == dict.keys()
    list(dict.iteritems()) = dict.items()
    list(xrange(i, j, k)) == range(i, j, k)
diff --git a/Objects/abstract.c b/Objects/abstract.c
index f656747..a5f97a1 100644
--- a/Objects/abstract.c
+++ b/Objects/abstract.c
@@ -1236,52 +1236,78 @@
 PyObject *
 PySequence_List(PyObject *v)
 {
-	PySequenceMethods *m;
+	PyObject *it;      /* iter(v) */
+	PyObject *result;  /* result list */
+	int n;		   /* guess for result list size */
+	int i;
 
 	if (v == NULL)
 		return null_error();
 
+	/* Special-case list(a_list), for speed. */
 	if (PyList_Check(v))
 		return PyList_GetSlice(v, 0, PyList_GET_SIZE(v));
 
-	m = v->ob_type->tp_as_sequence;
-	if (m && m->sq_item) {
-		int i;
-		PyObject *l;
-		int n = PySequence_Size(v);
+	/* Get iterator.  There may be some low-level efficiency to be gained
+	 * by caching the tp_iternext slot instead of using PyIter_Next()
+	 * later, but premature optimization is the root etc.
+	 */
+	it = PyObject_GetIter(v);
+	if (it == NULL)
+		return NULL;
+
+	/* Guess a result list size. */
+	n = -1;	 /* unknown */
+	if (PySequence_Check(v) &&
+	    v->ob_type->tp_as_sequence->sq_length) {
+		n = PySequence_Size(v);
 		if (n < 0)
-			return NULL;
-		l = PyList_New(n);
-		if (l == NULL)
-			return NULL;
-		for (i = 0; ; i++) {
-			PyObject *item = (*m->sq_item)(v, i);
-			if (item == NULL) {
-				if (PyErr_ExceptionMatches(PyExc_IndexError))
+			PyErr_Clear();
+	}
+	if (n < 0)
+		n = 8;	/* arbitrary */
+	result = PyList_New(n);
+	if (result == NULL) {
+		Py_DECREF(it);
+		return NULL;
+	}
+
+	/* Run iterator to exhaustion. */
+	for (i = 0; ; i++) {
+		PyObject *item = PyIter_Next(it);
+		if (item == NULL) {
+			/* We're out of here in any case, but if this is a
+			 * StopIteration exception it's expected, but if
+			 * any other kind of exception it's an error.
+			 */
+			if (PyErr_Occurred()) {
+				if (PyErr_ExceptionMatches(PyExc_StopIteration))
 					PyErr_Clear();
 				else {
-					Py_DECREF(l);
-					l = NULL;
+					Py_DECREF(result);
+					result = NULL;
 				}
-				break;
 			}
-			if (i < n)
-				PyList_SET_ITEM(l, i, item);
-			else if (PyList_Append(l, item) < 0) {
-				Py_DECREF(l);
-				l = NULL;
-				break;
-			}
+			break;
 		}
-		if (i < n && l != NULL) {
-			if (PyList_SetSlice(l, i, n, (PyObject *)NULL) != 0) {
-				Py_DECREF(l);
-				l = NULL;
-			}
+		if (i < n)
+			PyList_SET_ITEM(result, i, item);
+		else if (PyList_Append(result, item) < 0) {
+			Py_DECREF(result);
+			result = NULL;
+			break;
 		}
-		return l;
 	}
-	return type_error("list() argument must be a sequence");
+
+	/* Cut back result list if initial guess was too large. */
+	if (i < n && result != NULL) {
+		if (PyList_SetSlice(result, i, n, (PyObject *)NULL) != 0) {
+			Py_DECREF(result);
+			result = NULL;
+		}
+	}
+	Py_DECREF(it);
+	return result;
 }
 
 PyObject *