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.
diff --git a/Include/abstract.h b/Include/abstract.h
index c56c887..1dae5f1 100644
--- a/Include/abstract.h
+++ b/Include/abstract.h
@@ -470,11 +470,24 @@
*/
+/* Iterators */
+
DL_IMPORT(PyObject *) PyObject_GetIter(PyObject *);
/* Takes an object and returns an iterator for it.
This is typically a new iterator but if the argument
is an iterator, this returns itself. */
+#define PyIter_Check(obj) \
+ (PyType_HasFeature((obj)->ob_type, Py_TPFLAGS_HAVE_ITER) && \
+ (obj)->ob_type->tp_iternext != NULL)
+
+ DL_IMPORT(PyObject *) PyIter_Next(PyObject *);
+ /* Takes an iterator object and calls its tp_iternext slot,
+ returning the next value. If the iterator is exhausted,
+ this can return NULL without setting an exception, *or*
+ NULL with a StopIteration exception.
+ NULL with any other exception means an error occurred. */
+
/* Number Protocol:*/
DL_IMPORT(int) PyNumber_Check(PyObject *o);