Skip to content

Commit 6ec0996

Browse files
committed
SF patch #907403: Improvements to cStringIO.writelines()
The writelines() method now accepts any iterable argument and writes the lines one at a time rather than using ''.join(lines) followed by a single write. Results in considerable memory savings and makes the method suitable for use with generator expressions.
1 parent 73360a3 commit 6ec0996

2 files changed

Lines changed: 27 additions & 30 deletions

File tree

‎Lib/StringIO.py‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -178,8 +178,10 @@ def write(self, s):
178178
self.len = newpos
179179
self.pos = newpos
180180

181-
def writelines(self, list):
182-
self.write(''.join(list))
181+
def writelines(self, iterable):
182+
write = self.write
183+
for line in iterable:
184+
write(line)
183185

184186
def flush(self):
185187
_complain_ifclosed(self.closed)

‎Modules/cStringIO.c‎

Lines changed: 23 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -416,40 +416,35 @@ O_close(Oobject *self, PyObject *unused) {
416416
return Py_None;
417417
}
418418

419-
420419
PyDoc_STRVAR(O_writelines__doc__,
421-
"writelines(sequence_of_strings): write each string");
420+
"writelines(sequence_of_strings) -> None. Write the strings to the file.\n"
421+
"\n"
422+
"Note that newlines are not added. The sequence can be any iterable object\n"
423+
"producing strings. This is equivalent to calling write() for each string.");
422424
static PyObject *
423425
O_writelines(Oobject *self, PyObject *args) {
424-
PyObject *tmp = 0;
425-
static PyObject *joiner = NULL;
426-
427-
if (!joiner) {
428-
PyObject *empty_string = PyString_FromString("");
429-
if (empty_string == NULL)
426+
PyObject *it, *s;
427+
428+
it = PyObject_GetIter(args);
429+
if (it == NULL)
430+
return NULL;
431+
while ((s = PyIter_Next(it)) != NULL) {
432+
int n;
433+
char *c;
434+
if (PyString_AsStringAndSize(s, &c, &n) == -1) {
435+
Py_DECREF(it);
436+
Py_DECREF(s);
430437
return NULL;
431-
joiner = PyObject_GetAttrString(empty_string, "join");
432-
Py_DECREF(empty_string);
433-
if (joiner == NULL)
438+
}
439+
if (O_cwrite((PyObject *)self, c, n) == -1) {
440+
Py_DECREF(it);
441+
Py_DECREF(s);
434442
return NULL;
443+
}
444+
Py_DECREF(s);
435445
}
436-
437-
if (PyObject_Size(args) < 0) return NULL;
438-
439-
args = PyTuple_Pack(1, args);
440-
if (args == NULL)
441-
return NULL;
442-
tmp = PyObject_Call(joiner, args, NULL);
443-
Py_DECREF(args);
444-
UNLESS (tmp) return NULL;
445-
446-
args = PyTuple_Pack(1, tmp);
447-
Py_DECREF(tmp);
448-
UNLESS (args) return NULL;
449-
450-
tmp = O_write(self, args);
451-
Py_DECREF(args);
452-
return tmp;
446+
Py_DECREF(it);
447+
Py_RETURN_NONE;
453448
}
454449

455450
static struct PyMethodDef O_methods[] = {

0 commit comments

Comments
 (0)