When they mention that trick in the documentation, they don't expect that you fiddle with the iterator first.
Yes, this is expected (and useful, when you want to skip a title line for instance, then read the rest of the lines).
If you want to be sure to read all the lines just rewind the file prior to calling readlines
:
f.seek(0)
lines = f.readlines()
The documentation is a bit scarce about readlines
not rewinding the file. I did quite a lot of googling, it just seems implied & natural. If you're not still convinced, you have to take a look at the source code (bytesio.c
from Python 3.6.1 source):
static PyObject *
_io_BytesIO_readlines_impl(bytesio *self, PyObject *arg)
/*[clinic end generated code: output=09b8e34c880808ff input=691aa1314f2c2a87]*/
{
Py_ssize_t maxsize, size, n;
PyObject *result, *line;
char *output;
CHECK_CLOSED(self);
if (PyLong_Check(arg)) {
maxsize = PyLong_AsSsize_t(arg);
if (maxsize == -1 && PyErr_Occurred())
return NULL;
}
else if (arg == Py_None) {
/* No size limit, by default. */
maxsize = -1;
}
else {
PyErr_Format(PyExc_TypeError, "integer argument expected, got '%s'",
Py_TYPE(arg)->tp_name);
return NULL;
}
size = 0;
result = PyList_New(0);
if (!result)
return NULL;
output = PyBytes_AS_STRING(self->buf) + self->pos;
while ((n = scan_eol(self, -1)) != 0) {
self->pos += n;
I stopped pasting just after the readline loop started. On the line above, we see that the code is using the current self->pos
value of the object. And it is not reset in the beginning of the code.