diff options
author | Guido van Rossum <guido@python.org> | 2001-04-23 14:08:49 (GMT) |
---|---|---|
committer | Guido van Rossum <guido@python.org> | 2001-04-23 14:08:49 (GMT) |
commit | 213c7a6aa5889f42495352199715a1c1a0833a00 (patch) | |
tree | 7559cd072f732c861cb28adb7192561a877fd6fb /Objects/classobject.c | |
parent | 8b3d6ca3df1097752a1091b2c8f6d7de1b36a81d (diff) | |
download | cpython-213c7a6aa5889f42495352199715a1c1a0833a00.zip cpython-213c7a6aa5889f42495352199715a1c1a0833a00.tar.gz cpython-213c7a6aa5889f42495352199715a1c1a0833a00.tar.bz2 |
Mondo changes to the iterator stuff, without changing how Python code
sees it (test_iter.py is unchanged).
- Added a tp_iternext slot, which calls the iterator's next() method;
this is much faster for built-in iterators over built-in types
such as lists and dicts, speeding up pybench's ForLoop with about
25% compared to Python 2.1. (Now there's a good argument for
iterators. ;-)
- Renamed the built-in sequence iterator SeqIter, affecting the C API
functions for it. (This frees up the PyIter prefix for generic
iterator operations.)
- Added PyIter_Check(obj), which checks that obj's type has a
tp_iternext slot and that the proper feature flag is set.
- Added PyIter_Next(obj) which calls the tp_iternext slot. It has a
somewhat complex return condition due to the need for speed: when it
returns NULL, it may not have set an exception condition, meaning
the iterator is exhausted; when the exception StopIteration is set
(or a derived exception class), it means the same thing; any other
exception means some other error occurred.
Diffstat (limited to 'Objects/classobject.c')
-rw-r--r-- | Objects/classobject.c | 40 |
1 files changed, 38 insertions, 2 deletions
diff --git a/Objects/classobject.c b/Objects/classobject.c index 742e472..80b7ae5 100644 --- a/Objects/classobject.c +++ b/Objects/classobject.c @@ -848,7 +848,8 @@ instance_traverse(PyInstanceObject *o, visitproc visit, void *arg) return 0; } -static PyObject *getitemstr, *setitemstr, *delitemstr, *lenstr, *iterstr; +static PyObject *getitemstr, *setitemstr, *delitemstr, *lenstr; +static PyObject *iterstr, *nextstr; static int instance_length(PyInstanceObject *inst) @@ -1726,6 +1727,14 @@ instance_getiter(PyInstanceObject *self) if ((func = instance_getattr(self, iterstr)) != NULL) { PyObject *res = PyEval_CallObject(func, (PyObject *)NULL); Py_DECREF(func); + if (res != NULL && !PyIter_Check(res)) { + PyErr_Format(PyExc_TypeError, + "__iter__ returned non-iterator " + "of type '%.100s'", + res->ob_type->tp_name); + Py_DECREF(res); + res = NULL; + } return res; } PyErr_Clear(); @@ -1734,7 +1743,33 @@ instance_getiter(PyInstanceObject *self) return NULL; } Py_DECREF(func); - return PyIter_New((PyObject *)self); + return PySeqIter_New((PyObject *)self); +} + + +/* Call the iterator's next */ +static PyObject * +instance_iternext(PyInstanceObject *self) +{ + PyObject *func; + + if (nextstr == NULL) + nextstr = PyString_InternFromString("next"); + + if ((func = instance_getattr(self, nextstr)) != NULL) { + PyObject *res = PyEval_CallObject(func, (PyObject *)NULL); + Py_DECREF(func); + if (res != NULL) { + return res; + } + if (PyErr_ExceptionMatches(PyExc_StopIteration)) { + PyErr_Clear(); + return NULL; + } + return NULL; + } + PyErr_SetString(PyExc_TypeError, "instance has no next() method"); + return NULL; } @@ -1803,6 +1838,7 @@ PyTypeObject PyInstance_Type = { instance_richcompare, /* tp_richcompare */ offsetof(PyInstanceObject, in_weakreflist), /* tp_weaklistoffset */ (getiterfunc)instance_getiter, /* tp_iter */ + (iternextfunc)instance_iternext, /* tp_iternext */ }; |