Jeff Epler's xreadlines module, with slight reformatting and some
changes for safety and tuning.
diff --git a/Modules/Setup.dist b/Modules/Setup.dist
index e46eca4..53ab1fb 100644
--- a/Modules/Setup.dist
+++ b/Modules/Setup.dist
@@ -156,6 +156,9 @@
 # Memory-mapped files (also works on Win32).
 mmap mmapmodule.c
 
+# Dynamic readlines
+xreadlines xreadlinesmodule.c
+
 # Socket module compiled with SSL support; you must edit the SSL variable:
 #SSL=/usr/local/ssl
 #_socket socketmodule.c \
diff --git a/Modules/xreadlinesmodule.c b/Modules/xreadlinesmodule.c
new file mode 100644
index 0000000..c50dd06
--- /dev/null
+++ b/Modules/xreadlinesmodule.c
@@ -0,0 +1,118 @@
+#include "Python.h"
+
+static char xreadlines_doc [] =
+"xreadlines(f)\n\
+\n\
+Return an xreadlines object for the file f.";
+
+typedef struct {
+	PyObject_HEAD
+	PyObject *file;
+	PyObject *lines;
+	int lineslen;
+	int lineno;
+	int abslineno;
+} PyXReadlinesObject;
+
+staticforward PyTypeObject XReadlinesObject_Type;
+
+static void
+xreadlines_dealloc(PyXReadlinesObject *op) {
+	Py_XDECREF(op->file);
+	Py_XDECREF(op->lines);
+	PyObject_DEL(op);
+}
+
+/* A larger chunk size doesn't seem to make a difference */
+#define CHUNKSIZE  8192
+
+static PyXReadlinesObject *
+newreadlinesobject(PyObject *file) {
+	PyXReadlinesObject *op;
+	op = PyObject_NEW(PyXReadlinesObject, &XReadlinesObject_Type);
+	if (op == NULL)
+		return NULL;
+	Py_XINCREF(file);
+	op->file = file;
+	op->lines = NULL;
+	op->abslineno = op->lineno = op->lineslen = 0;
+	return op;
+}
+
+static PyObject *
+xreadlines(PyObject *self, PyObject *args) {
+	PyObject *file;
+	PyXReadlinesObject *ret;
+
+	if (!PyArg_ParseTuple(args, "O:xreadlines", &file))
+		return NULL;
+	ret = newreadlinesobject(file);
+	Py_XINCREF(ret);
+	return (PyObject*)ret;
+}
+
+static PyObject*
+xreadlines_item(PyXReadlinesObject *a, int i) {
+	if (i != a->abslineno) {
+		PyErr_SetString(PyExc_RuntimeError,
+			"xreadlines object accessed out of order");
+		return NULL;
+	}
+	if (a->lineno >= a->lineslen) {
+		Py_XDECREF(a->lines);
+		a->lines = PyObject_CallMethod(a->file, "readlines", "(i)",
+					       CHUNKSIZE);
+		if (a->lines == NULL)
+			return NULL;
+		a->lineno = 0;
+		if ((a->lineslen = PySequence_Size(a->lines)) < 0)
+			return NULL;
+	}
+	a->abslineno++;
+	return PySequence_GetItem(a->lines, a->lineno++);
+}
+
+static PySequenceMethods xreadlines_as_sequence = {
+	0, /*sq_length*/
+	0, /*sq_concat*/
+	0, /*sq_repeat*/
+	(intargfunc)xreadlines_item, /*sq_item*/
+};
+
+static PyTypeObject XReadlinesObject_Type = {
+	PyObject_HEAD_INIT(&PyType_Type)
+	0,
+	"xreadlines",
+	sizeof(PyXReadlinesObject) + PyGC_HEAD_SIZE,
+	0,
+	(destructor)xreadlines_dealloc, /*tp_dealloc*/
+	0, /*tp_print*/
+	0, /*tp_getattr*/
+	0, /*tp_setattr*/
+	0, /*tp_compare*/
+	0, /*tp_repr*/
+	0, /*tp_as_number*/
+	&xreadlines_as_sequence, /*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,	/*tp_flags*/
+ 	0,		/* tp_doc */
+};
+
+static PyMethodDef xreadlines_methods[] = {
+	{"xreadlines", xreadlines, METH_VARARGS, xreadlines_doc},
+	{NULL, NULL}
+};
+
+void
+initxreadlines(void)
+{
+	PyObject *m;
+
+	m = Py_InitModule("xreadlines", xreadlines_methods);
+}