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)
This commit is contained in:
Tim Peters 2001-05-01 20:45:31 +00:00
parent 47668928e6
commit f553f89d45
3 changed files with 99 additions and 31 deletions

View file

@ -1236,52 +1236,78 @@ PySequence_Tuple(PyObject *v)
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 *