Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit f4848da

Browse files
committed
Make PyIter_Next() a little smarter (wrt its knowledge of iterator
internals) so clients can be a lot dumber (wrt their knowledge).
1 parent 648b4de commit f4848da

4 files changed

Lines changed: 35 additions & 66 deletions

File tree

Include/abstract.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -484,9 +484,8 @@ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx*/
484484
DL_IMPORT(PyObject *) PyIter_Next(PyObject *);
485485
/* Takes an iterator object and calls its tp_iternext slot,
486486
returning the next value. If the iterator is exhausted,
487-
this can return NULL without setting an exception, *or*
488-
NULL with a StopIteration exception.
489-
NULL with any other exception means an error occurred. */
487+
this returns NULL without setting an exception.
488+
NULL with an exception means an error occurred. */
490489

491490
/* Number Protocol:*/
492491

Objects/abstract.c

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1276,17 +1276,9 @@ PySequence_List(PyObject *v)
12761276
for (i = 0; ; i++) {
12771277
PyObject *item = PyIter_Next(it);
12781278
if (item == NULL) {
1279-
/* We're out of here in any case, but if this is a
1280-
* StopIteration exception it's expected, but if
1281-
* any other kind of exception it's an error.
1282-
*/
12831279
if (PyErr_Occurred()) {
1284-
if (PyErr_ExceptionMatches(PyExc_StopIteration))
1285-
PyErr_Clear();
1286-
else {
1287-
Py_DECREF(result);
1288-
result = NULL;
1289-
}
1280+
Py_DECREF(result);
1281+
result = NULL;
12901282
}
12911283
break;
12921284
}
@@ -1796,14 +1788,27 @@ PyObject_GetIter(PyObject *o)
17961788
}
17971789
}
17981790

1791+
/* Return next item.
1792+
* If an error occurs, return NULL. PyErr_Occurred() will be true.
1793+
* If the iteration terminates normally, return NULL and clear the
1794+
* PyExc_StopIteration exception (if it was set). PyErr_Occurred()
1795+
* will be false.
1796+
* Else return the next object. PyErr_Occurred() will be false.
1797+
*/
17991798
PyObject *
18001799
PyIter_Next(PyObject *iter)
18011800
{
1801+
PyObject *result;
18021802
if (!PyIter_Check(iter)) {
18031803
PyErr_Format(PyExc_TypeError,
18041804
"'%.100s' object is not an iterator",
18051805
iter->ob_type->tp_name);
18061806
return NULL;
18071807
}
1808-
return (*iter->ob_type->tp_iternext)(iter);
1808+
result = (*iter->ob_type->tp_iternext)(iter);
1809+
if (result == NULL &&
1810+
PyErr_Occurred() &&
1811+
PyErr_ExceptionMatches(PyExc_StopIteration))
1812+
PyErr_Clear();
1813+
return result;
18091814
}

Python/bltinmodule.c

Lines changed: 14 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ builtin_filter(PyObject *self, PyObject *args)
164164
{
165165
PyObject *func, *seq, *result, *it;
166166
int len; /* guess for result list size */
167-
register int i, j;
167+
register int j;
168168

169169
if (!PyArg_ParseTuple(args, "OO:filter", &func, &seq))
170170
return NULL;
@@ -204,22 +204,15 @@ builtin_filter(PyObject *self, PyObject *args)
204204
}
205205

206206
/* Build the result list. */
207-
for (i = j = 0; ; ++i) {
207+
j = 0;
208+
for (;;) {
208209
PyObject *item, *good;
209210
int ok;
210211

211212
item = PyIter_Next(it);
212213
if (item == NULL) {
213-
/* We're out of here in any case, but if this is a
214-
* StopIteration exception it's expected, but if
215-
* any other kind of exception it's an error.
216-
*/
217-
if (PyErr_Occurred()) {
218-
if (PyErr_ExceptionMatches(PyExc_StopIteration))
219-
PyErr_Clear();
220-
else
221-
goto Fail_result_it;
222-
}
214+
if (PyErr_Occurred())
215+
goto Fail_result_it;
223216
break;
224217
}
225218

@@ -1030,24 +1023,14 @@ builtin_map(PyObject *self, PyObject *args)
10301023
if (item)
10311024
++numactive;
10321025
else {
1033-
/* StopIteration is *implied* by a
1034-
* NULL return from PyIter_Next() if
1035-
* PyErr_Occurred() is false.
1036-
*/
10371026
if (PyErr_Occurred()) {
1038-
if (PyErr_ExceptionMatches(
1039-
PyExc_StopIteration))
1040-
PyErr_Clear();
1041-
else {
1042-
Py_XDECREF(alist);
1043-
goto Fail_1;
1044-
}
1027+
Py_XDECREF(alist);
1028+
goto Fail_1;
10451029
}
10461030
Py_INCREF(Py_None);
10471031
item = Py_None;
10481032
sqp->saw_StopIteration = 1;
10491033
}
1050-
10511034
}
10521035
if (alist)
10531036
PyTuple_SET_ITEM(alist, j, item);
@@ -1445,7 +1428,6 @@ Return the dictionary containing the current scope's local variables.";
14451428
static PyObject *
14461429
min_max(PyObject *args, int op)
14471430
{
1448-
int i;
14491431
PyObject *v, *w, *x, *it;
14501432

14511433
if (PyTuple_Size(args) > 1)
@@ -1458,21 +1440,13 @@ min_max(PyObject *args, int op)
14581440
return NULL;
14591441

14601442
w = NULL; /* the result */
1461-
for (i = 0; ; i++) {
1443+
for (;;) {
14621444
x = PyIter_Next(it);
14631445
if (x == NULL) {
1464-
/* We're out of here in any case, but if this is a
1465-
* StopIteration exception it's expected, but if
1466-
* any other kind of exception it's an error.
1467-
*/
14681446
if (PyErr_Occurred()) {
1469-
if (PyErr_ExceptionMatches(PyExc_StopIteration))
1470-
PyErr_Clear();
1471-
else {
1472-
Py_XDECREF(w);
1473-
Py_DECREF(it);
1474-
return NULL;
1475-
}
1447+
Py_XDECREF(w);
1448+
Py_DECREF(it);
1449+
return NULL;
14761450
}
14771451
break;
14781452
}
@@ -1880,16 +1854,9 @@ builtin_reduce(PyObject *self, PyObject *args)
18801854

18811855
op2 = PyIter_Next(it);
18821856
if (op2 == NULL) {
1883-
/* StopIteration is *implied* by a NULL return from
1884-
* PyIter_Next() if PyErr_Occurred() is false.
1885-
*/
1886-
if (PyErr_Occurred()) {
1887-
if (PyErr_ExceptionMatches(PyExc_StopIteration))
1888-
PyErr_Clear();
1889-
else
1890-
goto Fail;
1891-
}
1892-
break;
1857+
if (PyErr_Occurred())
1858+
goto Fail;
1859+
break;
18931860
}
18941861

18951862
if (result == NULL)

Python/ceval.c

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1894,11 +1894,9 @@ eval_code2(PyCodeObject *co, PyObject *globals, PyObject *locals,
18941894
PUSH(x);
18951895
continue;
18961896
}
1897-
if (!PyErr_Occurred() ||
1898-
PyErr_ExceptionMatches(
1899-
PyExc_StopIteration))
1900-
{
1901-
x = v = POP();
1897+
if (!PyErr_Occurred()) {
1898+
/* iterator ended normally */
1899+
x = v = POP();
19021900
Py_DECREF(v);
19031901
JUMPBY(oparg);
19041902
continue;

0 commit comments

Comments
 (0)