Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>Below is a simple implementation of module <code>spam</code> with one function <code>myiter(int)</code> returning iterator:</p> <pre><code>import spam for i in spam.myiter(10): print i </code></pre> <p>prints numbers from 0 to 9.</p> <p>It is simpler then your case but shows main points: defining object with standard <code>__iter__()</code> and <code>next()</code> methods, and implementing iterator behaviour including raising <code>StopIteration</code> when appropriate.</p> <p>In your case iterator object needs to hold reference to Sequence (so you'll need deallocator method for it to Py_DECREF it). The sequence itself needs to implement <code>__iter()__</code> and create an iterator inside it.</p> <hr> <p>Structure containing state of iterator. (In your version instead of m, it would have reference to Sequence.)</p> <pre><code>typedef struct { PyObject_HEAD long int m; long int i; } spam_MyIter; </code></pre> <p>Iterator's <code>__iter__()</code> method. It always simply returns <code>self</code>. It allows for both iterator and collection to be treated the same in constructs like <code>for ... in ...</code>.</p> <pre><code>PyObject* spam_MyIter_iter(PyObject *self) { Py_INCREF(self); return self; } </code></pre> <p>Implementation of our iteration: <code>next()</code> method.</p> <pre><code>PyObject* spam_MyIter_iternext(PyObject *self) { spam_MyIter *p = (spam_MyIter *)self; if (p-&gt;i &lt; p-&gt;m) { PyObject *tmp = Py_BuildValue("l", p-&gt;i); (p-&gt;i)++; return tmp; } else { /* Raising of standard StopIteration exception with empty value. */ PyErr_SetNone(PyExc_StopIteration); return NULL; } } </code></pre> <p>We need extended version of <code>PyTypeObject</code> structure to provide Python with information about <code>__iter__()</code> and <code>next()</code>. We want them to be called efficiently, so no name-based lookup in dictionary.</p> <pre><code>static PyTypeObject spam_MyIterType = { PyObject_HEAD_INIT(NULL) 0, /*ob_size*/ "spam._MyIter", /*tp_name*/ sizeof(spam_MyIter), /*tp_basicsize*/ 0, /*tp_itemsize*/ 0, /*tp_dealloc*/ 0, /*tp_print*/ 0, /*tp_getattr*/ 0, /*tp_setattr*/ 0, /*tp_compare*/ 0, /*tp_repr*/ 0, /*tp_as_number*/ 0, /*tp_as_sequence*/ 0, /*tp_as_mapping*/ 0, /*tp_hash */ 0, /*tp_call*/ 0, /*tp_str*/ 0, /*tp_getattro*/ 0, /*tp_setattro*/ 0, /*tp_as_buffer*/ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_ITER, /* tp_flags: Py_TPFLAGS_HAVE_ITER tells python to use tp_iter and tp_iternext fields. */ "Internal myiter iterator object.", /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ 0, /* tp_richcompare */ 0, /* tp_weaklistoffset */ spam_MyIter_iter, /* tp_iter: __iter__() method */ spam_MyIter_iternext /* tp_iternext: next() method */ }; </code></pre> <p><code>myiter(int)</code> function creates iterator.</p> <pre><code>static PyObject * spam_myiter(PyObject *self, PyObject *args) { long int m; spam_MyIter *p; if (!PyArg_ParseTuple(args, "l", &amp;m)) return NULL; /* I don't need python callable __init__() method for this iterator, so I'll simply allocate it as PyObject and initialize it by hand. */ p = PyObject_New(spam_MyIter, &amp;spam_MyIterType); if (!p) return NULL; /* I'm not sure if it's strictly necessary. */ if (!PyObject_Init((PyObject *)p, &amp;spam_MyIterType)) { Py_DECREF(p); return NULL; } p-&gt;m = m; p-&gt;i = 0; return (PyObject *)p; } </code></pre> <p>The rest is pretty boring...</p> <pre><code>static PyMethodDef SpamMethods[] = { {"myiter", spam_myiter, METH_VARARGS, "Iterate from i=0 while i&lt;m."}, {NULL, NULL, 0, NULL} /* Sentinel */ }; PyMODINIT_FUNC initspam(void) { PyObject* m; spam_MyIterType.tp_new = PyType_GenericNew; if (PyType_Ready(&amp;spam_MyIterType) &lt; 0) return; m = Py_InitModule("spam", SpamMethods); Py_INCREF(&amp;spam_MyIterType); PyModule_AddObject(m, "_MyIter", (PyObject *)&amp;spam_MyIterType); } </code></pre>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload