@@ -1164,55 +1164,54 @@ file_write(PyFileObject *f, PyObject *args)
11641164}
11651165
11661166static PyObject *
1167- file_writelines (PyFileObject * f , PyObject * args )
1167+ file_writelines (PyFileObject * f , PyObject * seq )
11681168{
11691169#define CHUNKSIZE 1000
11701170 PyObject * list , * line ;
1171+ PyObject * it ; /* iter(seq) */
11711172 PyObject * result ;
11721173 int i , j , index , len , nwritten , islist ;
11731174
1175+ assert (seq != NULL );
11741176 if (f -> f_fp == NULL )
11751177 return err_closed ();
1176- if (args == NULL || !PySequence_Check (args )) {
1177- PyErr_SetString (PyExc_TypeError ,
1178- "writelines() argument must be a sequence of strings" );
1179- return NULL ;
1180- }
1181- islist = PyList_Check (args );
11821178
1183- /* Strategy: slurp CHUNKSIZE lines into a private list,
1184- checking that they are all strings, then write that list
1185- without holding the interpreter lock, then come back for more. */
1186- index = 0 ;
1187- if (islist )
1188- list = NULL ;
1179+ result = NULL ;
1180+ list = NULL ;
1181+ islist = PyList_Check (seq );
1182+ if (islist )
1183+ it = NULL ;
11891184 else {
1185+ it = PyObject_GetIter (seq );
1186+ if (it == NULL ) {
1187+ PyErr_SetString (PyExc_TypeError ,
1188+ "writelines() requires an iterable argument" );
1189+ return NULL ;
1190+ }
1191+ /* From here on, fail by going to error, to reclaim "it". */
11901192 list = PyList_New (CHUNKSIZE );
11911193 if (list == NULL )
1192- return NULL ;
1194+ goto error ;
11931195 }
1194- result = NULL ;
11951196
1196- for (;;) {
1197+ /* Strategy: slurp CHUNKSIZE lines into a private list,
1198+ checking that they are all strings, then write that list
1199+ without holding the interpreter lock, then come back for more. */
1200+ for (index = 0 ; ; index += CHUNKSIZE ) {
11971201 if (islist ) {
11981202 Py_XDECREF (list );
1199- list = PyList_GetSlice (args , index , index + CHUNKSIZE );
1203+ list = PyList_GetSlice (seq , index , index + CHUNKSIZE );
12001204 if (list == NULL )
1201- return NULL ;
1205+ goto error ;
12021206 j = PyList_GET_SIZE (list );
12031207 }
12041208 else {
12051209 for (j = 0 ; j < CHUNKSIZE ; j ++ ) {
1206- line = PySequence_GetItem ( args , index + j );
1210+ line = PyIter_Next ( it );
12071211 if (line == NULL ) {
1208- if (PyErr_ExceptionMatches (
1209- PyExc_IndexError )) {
1210- PyErr_Clear ();
1211- break ;
1212- }
1213- /* Some other error occurred.
1214- XXX We may lose some output. */
1215- goto error ;
1212+ if (PyErr_Occurred ())
1213+ goto error ;
1214+ break ;
12161215 }
12171216 PyList_SetItem (list , j , line );
12181217 }
@@ -1271,14 +1270,15 @@ file_writelines(PyFileObject *f, PyObject *args)
12711270
12721271 if (j < CHUNKSIZE )
12731272 break ;
1274- index += CHUNKSIZE ;
12751273 }
12761274
12771275 Py_INCREF (Py_None );
12781276 result = Py_None ;
12791277 error :
12801278 Py_XDECREF (list );
1279+ Py_XDECREF (it );
12811280 return result ;
1281+ #undef CHUNKSIZE
12821282}
12831283
12841284static char readline_doc [] =
@@ -1342,10 +1342,10 @@ static char xreadlines_doc[] =
13421342"often quicker, due to reading ahead internally." ;
13431343
13441344static char writelines_doc [] =
1345- "writelines(list of strings ) -> None. Write the strings to the file.\n"
1345+ "writelines(sequence_of_strings ) -> None. Write the strings to the file.\n"
13461346"\n"
1347- "Note that newlines are not added. This is equivalent to calling write() \n"
1348- "for each string in the list ." ;
1347+ "Note that newlines are not added. The sequence can be any iterable object \n"
1348+ "producing strings. This is equivalent to calling write() for each string ." ;
13491349
13501350static char flush_doc [] =
13511351"flush() -> None. Flush the internal I/O buffer." ;
0 commit comments