From 49f9bd15ffeef67358a319f89faeaa31ad97d575 Mon Sep 17 00:00:00 2001 From: Raymond Hettinger Date: Sun, 14 Mar 2004 05:43:59 +0000 Subject: SF feature request #686323: Minor array module enhancements array.extend() now accepts iterable arguments implements as a series of appends. Besides being a user convenience and matching the behavior for lists, this the saves memory and cycles that would be used to create a temporary array object. --- Doc/lib/libarray.tex | 11 +++++++---- Lib/test/test_array.py | 7 +++++++ Misc/NEWS | 4 +++- Modules/arraymodule.c | 43 ++++++++++++++++++++++++++++++++++--------- 4 files changed, 51 insertions(+), 14 deletions(-) diff --git a/Doc/lib/libarray.tex b/Doc/lib/libarray.tex index 6ec056f..6fd8b0c 100644 --- a/Doc/lib/libarray.tex +++ b/Doc/lib/libarray.tex @@ -104,10 +104,13 @@ data from a file written on a machine with a different byte order. Return the number of occurences of \var{x} in the array. \end{methoddesc} -\begin{methoddesc}[array]{extend}{a} -Append array items from \var{a} to the end of the array. The two -arrays must have \emph{exactly} the same type code; if not, -\exception{TypeError} will be raised. +\begin{methoddesc}[array]{extend}{iterable} +Append items from \var{iterable} to the end of the array. If +\var{iterable} is another array, it must have \emph{exactly} the same +type code; if not, \exception{TypeError} will be raised. If +\var{iterable} is not an array, it must be iterable and its +elements must be the right type to be appended to the array. +\versionchanged[Formerly, the argument could only be another array]{2.4} \end{methoddesc} \begin{methoddesc}[array]{fromfile}{f, n} diff --git a/Lib/test/test_array.py b/Lib/test/test_array.py index c9b05c2..0f3e07f 100755 --- a/Lib/test/test_array.py +++ b/Lib/test/test_array.py @@ -592,6 +592,13 @@ class BaseTest(unittest.TestCase): b = array.array(self.badtypecode()) self.assertRaises(TypeError, a.extend, b) + a = array.array(self.typecode, self.example) + a.extend(self.example[::-1]) + self.assertEqual( + a, + array.array(self.typecode, self.example+self.example[::-1]) + ) + def test_coveritertraverse(self): try: import gc diff --git a/Misc/NEWS b/Misc/NEWS index dfe6e2f..d4aef1e 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -182,7 +182,9 @@ Extension modules - array objects now support the copy module. Also, their resizing scheme has been updated the same as for list objects. The improves - performance for append() operations. + the performance (speed and memory usage) of append() operations. + Also, array.extend() now accepts any iterable argument for repeated + appends without needing to create another temporary array. - cStringIO.writelines() now accepts any iterable argument and writes the lines one at a time rather than joining them and writing once. diff --git a/Modules/arraymodule.c b/Modules/arraymodule.c index 4c3c726..ed2ea9d 100644 --- a/Modules/arraymodule.c +++ b/Modules/arraymodule.c @@ -775,16 +775,35 @@ setarrayitem(PyObject *a, int i, PyObject *v) } static int -array_do_extend(arrayobject *self, PyObject *bb) +array_iter_extend(arrayobject *self, PyObject *bb) { - int size; + PyObject *it, *v; - if (!array_Check(bb)) { - PyErr_Format(PyExc_TypeError, - "can only extend array with array (not \"%.200s\")", - bb->ob_type->tp_name); + it = PyObject_GetIter(bb); + if (it == NULL) return -1; + + while ((v = PyIter_Next(it)) != NULL) { + if (ins1(self, (int) self->ob_size, v) != 0) { + Py_DECREF(v); + Py_DECREF(it); + return -1; + } + Py_DECREF(v); } + Py_DECREF(it); + if (PyErr_Occurred()) + return -1; + return 0; +} + +static int +array_do_extend(arrayobject *self, PyObject *bb) +{ + int size; + + if (!array_Check(bb)) + return array_iter_extend(self, bb); #define b ((arrayobject *)bb) if (self->ob_descr != b->ob_descr) { PyErr_SetString(PyExc_TypeError, @@ -810,6 +829,12 @@ array_do_extend(arrayobject *self, PyObject *bb) static PyObject * array_inplace_concat(arrayobject *self, PyObject *bb) { + if (!array_Check(bb)) { + PyErr_Format(PyExc_TypeError, + "can only extend array with array (not \"%.200s\")", + bb->ob_type->tp_name); + return NULL; + } if (array_do_extend(self, bb) == -1) return NULL; Py_INCREF(self); @@ -990,9 +1015,9 @@ array_extend(arrayobject *self, PyObject *bb) } PyDoc_STRVAR(extend_doc, -"extend(array)\n\ +"extend(array or iterable)\n\ \n\ - Append array items to the end of the array."); + Append items to the end of the array."); static PyObject * array_insert(arrayobject *self, PyObject *args) @@ -1881,7 +1906,7 @@ append() -- append a new item to the end of the array\n\ buffer_info() -- return information giving the current memory info\n\ byteswap() -- byteswap all the items of the array\n\ count() -- return number of occurences of an object\n\ -extend() -- extend array by appending array elements\n\ +extend() -- extend array by appending multiple elements from an iterable\n\ fromfile() -- read items from a file object\n\ fromlist() -- append items from the list\n\ fromstring() -- append items from the string\n\ -- cgit v0.12