Make PyIter_Next() a little smarter (wrt its knowledge of iterator

internals) so clients can be a lot dumber (wrt their knowledge).
This commit is contained in:
Tim Peters 2001-05-05 00:14:56 +00:00
parent 648b4de3d3
commit f4848dac41
4 changed files with 35 additions and 66 deletions

View File

@ -484,9 +484,8 @@ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx*/
DL_IMPORT(PyObject *) PyIter_Next(PyObject *); DL_IMPORT(PyObject *) PyIter_Next(PyObject *);
/* Takes an iterator object and calls its tp_iternext slot, /* Takes an iterator object and calls its tp_iternext slot,
returning the next value. If the iterator is exhausted, returning the next value. If the iterator is exhausted,
this can return NULL without setting an exception, *or* this returns NULL without setting an exception.
NULL with a StopIteration exception. NULL with an exception means an error occurred. */
NULL with any other exception means an error occurred. */
/* Number Protocol:*/ /* Number Protocol:*/

View File

@ -1276,17 +1276,9 @@ PySequence_List(PyObject *v)
for (i = 0; ; i++) { for (i = 0; ; i++) {
PyObject *item = PyIter_Next(it); PyObject *item = PyIter_Next(it);
if (item == NULL) { 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_Occurred()) {
if (PyErr_ExceptionMatches(PyExc_StopIteration)) Py_DECREF(result);
PyErr_Clear(); result = NULL;
else {
Py_DECREF(result);
result = NULL;
}
} }
break; break;
} }
@ -1796,14 +1788,27 @@ PyObject_GetIter(PyObject *o)
} }
} }
/* Return next item.
* If an error occurs, return NULL. PyErr_Occurred() will be true.
* If the iteration terminates normally, return NULL and clear the
* PyExc_StopIteration exception (if it was set). PyErr_Occurred()
* will be false.
* Else return the next object. PyErr_Occurred() will be false.
*/
PyObject * PyObject *
PyIter_Next(PyObject *iter) PyIter_Next(PyObject *iter)
{ {
PyObject *result;
if (!PyIter_Check(iter)) { if (!PyIter_Check(iter)) {
PyErr_Format(PyExc_TypeError, PyErr_Format(PyExc_TypeError,
"'%.100s' object is not an iterator", "'%.100s' object is not an iterator",
iter->ob_type->tp_name); iter->ob_type->tp_name);
return NULL; return NULL;
} }
return (*iter->ob_type->tp_iternext)(iter); result = (*iter->ob_type->tp_iternext)(iter);
if (result == NULL &&
PyErr_Occurred() &&
PyErr_ExceptionMatches(PyExc_StopIteration))
PyErr_Clear();
return result;
} }

View File

@ -164,7 +164,7 @@ builtin_filter(PyObject *self, PyObject *args)
{ {
PyObject *func, *seq, *result, *it; PyObject *func, *seq, *result, *it;
int len; /* guess for result list size */ int len; /* guess for result list size */
register int i, j; register int j;
if (!PyArg_ParseTuple(args, "OO:filter", &func, &seq)) if (!PyArg_ParseTuple(args, "OO:filter", &func, &seq))
return NULL; return NULL;
@ -204,22 +204,15 @@ builtin_filter(PyObject *self, PyObject *args)
} }
/* Build the result list. */ /* Build the result list. */
for (i = j = 0; ; ++i) { j = 0;
for (;;) {
PyObject *item, *good; PyObject *item, *good;
int ok; int ok;
item = PyIter_Next(it); item = PyIter_Next(it);
if (item == NULL) { if (item == NULL) {
/* We're out of here in any case, but if this is a if (PyErr_Occurred())
* StopIteration exception it's expected, but if goto Fail_result_it;
* any other kind of exception it's an error.
*/
if (PyErr_Occurred()) {
if (PyErr_ExceptionMatches(PyExc_StopIteration))
PyErr_Clear();
else
goto Fail_result_it;
}
break; break;
} }
@ -1030,24 +1023,14 @@ builtin_map(PyObject *self, PyObject *args)
if (item) if (item)
++numactive; ++numactive;
else { else {
/* StopIteration is *implied* by a
* NULL return from PyIter_Next() if
* PyErr_Occurred() is false.
*/
if (PyErr_Occurred()) { if (PyErr_Occurred()) {
if (PyErr_ExceptionMatches( Py_XDECREF(alist);
PyExc_StopIteration)) goto Fail_1;
PyErr_Clear();
else {
Py_XDECREF(alist);
goto Fail_1;
}
} }
Py_INCREF(Py_None); Py_INCREF(Py_None);
item = Py_None; item = Py_None;
sqp->saw_StopIteration = 1; sqp->saw_StopIteration = 1;
} }
} }
if (alist) if (alist)
PyTuple_SET_ITEM(alist, j, item); PyTuple_SET_ITEM(alist, j, item);
@ -1445,7 +1428,6 @@ Return the dictionary containing the current scope's local variables.";
static PyObject * static PyObject *
min_max(PyObject *args, int op) min_max(PyObject *args, int op)
{ {
int i;
PyObject *v, *w, *x, *it; PyObject *v, *w, *x, *it;
if (PyTuple_Size(args) > 1) if (PyTuple_Size(args) > 1)
@ -1458,21 +1440,13 @@ min_max(PyObject *args, int op)
return NULL; return NULL;
w = NULL; /* the result */ w = NULL; /* the result */
for (i = 0; ; i++) { for (;;) {
x = PyIter_Next(it); x = PyIter_Next(it);
if (x == NULL) { if (x == 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_Occurred()) {
if (PyErr_ExceptionMatches(PyExc_StopIteration)) Py_XDECREF(w);
PyErr_Clear(); Py_DECREF(it);
else { return NULL;
Py_XDECREF(w);
Py_DECREF(it);
return NULL;
}
} }
break; break;
} }
@ -1880,16 +1854,9 @@ builtin_reduce(PyObject *self, PyObject *args)
op2 = PyIter_Next(it); op2 = PyIter_Next(it);
if (op2 == NULL) { if (op2 == NULL) {
/* StopIteration is *implied* by a NULL return from if (PyErr_Occurred())
* PyIter_Next() if PyErr_Occurred() is false. goto Fail;
*/ break;
if (PyErr_Occurred()) {
if (PyErr_ExceptionMatches(PyExc_StopIteration))
PyErr_Clear();
else
goto Fail;
}
break;
} }
if (result == NULL) if (result == NULL)

View File

@ -1894,11 +1894,9 @@ eval_code2(PyCodeObject *co, PyObject *globals, PyObject *locals,
PUSH(x); PUSH(x);
continue; continue;
} }
if (!PyErr_Occurred() || if (!PyErr_Occurred()) {
PyErr_ExceptionMatches( /* iterator ended normally */
PyExc_StopIteration)) x = v = POP();
{
x = v = POP();
Py_DECREF(v); Py_DECREF(v);
JUMPBY(oparg); JUMPBY(oparg);
continue; continue;