Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 8572b4f

Browse files
committed
Generalize zip() to work with iterators.
NEEDS DOC CHANGES. More AttributeErrors transmuted into TypeErrors, in test_b2.py, and, again, this strikes me as a good thing. This checkin completes the iterator generalization work that obviously needed to be done. Can anyone think of others that should be changed?
1 parent ef0c42d commit 8572b4f

4 files changed

Lines changed: 96 additions & 28 deletions

File tree

Lib/test/test_b2.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -309,13 +309,13 @@ class G:
309309
exc = 0
310310
try:
311311
zip(a, G())
312-
except AttributeError:
312+
except TypeError:
313313
exc = 1
314314
except:
315315
e = sys.exc_info()[0]
316316
raise TestFailed, 'zip(a, b) - b instance w/o __getitem__'
317317
if not exc:
318-
raise TestFailed, 'zip(a, b) - missing expected AttributeError'
318+
raise TestFailed, 'zip(a, b) - missing expected TypeError'
319319

320320

321321
# Epilogue -- unlink the temp file

Lib/test/test_iter.py

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -418,6 +418,52 @@ def test_builtin_map(self):
418418
except OSError:
419419
pass
420420

421+
# Test zip()'s use of iterators.
422+
def test_builtin_zip(self):
423+
self.assertRaises(TypeError, zip)
424+
self.assertRaises(TypeError, zip, None)
425+
self.assertRaises(TypeError, zip, range(10), 42)
426+
self.assertRaises(TypeError, zip, range(10), zip)
427+
428+
self.assertEqual(zip(IteratingSequenceClass(3)),
429+
[(0,), (1,), (2,)])
430+
self.assertEqual(zip(SequenceClass(3)),
431+
[(0,), (1,), (2,)])
432+
433+
d = {"one": 1, "two": 2, "three": 3}
434+
self.assertEqual(d.items(), zip(d, d.itervalues()))
435+
436+
# Generate all ints starting at constructor arg.
437+
class IntsFrom:
438+
def __init__(self, start):
439+
self.i = start
440+
441+
def __iter__(self):
442+
return self
443+
444+
def next(self):
445+
i = self.i
446+
self.i = i+1
447+
return i
448+
449+
f = open(TESTFN, "w")
450+
try:
451+
f.write("a\n" "bbb\n" "cc\n")
452+
finally:
453+
f.close()
454+
f = open(TESTFN, "r")
455+
try:
456+
self.assertEqual(zip(IntsFrom(0), f, IntsFrom(-100)),
457+
[(0, "a\n", -100),
458+
(1, "bbb\n", -99),
459+
(2, "cc\n", -98)])
460+
finally:
461+
f.close()
462+
try:
463+
unlink(TESTFN)
464+
except OSError:
465+
pass
466+
421467
# Test reduces()'s use of iterators.
422468
def test_builtin_reduce(self):
423469
from operator import add

Misc/NEWS

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,17 +17,13 @@ Core
1717

1818
- The following functions were generalized to work nicely with iterator
1919
arguments:
20-
filter()
21-
list()
22-
map()
23-
max()
24-
min()
25-
reduce()
26-
tuple() (PySequence_Tuple() and PySequence_Fast() in C API)
20+
map(), filter(), reduce()
21+
list(), tuple() (PySequence_Tuple() and PySequence_Fast() in C API)
22+
max(), min()
23+
zip()
2724
.join() method of strings
2825
'x in y' and 'x not in y' (PySequence_Contains() in C API)
2926
operator.countOf() (PySequence_Count() in C API)
30-
XXX TODO zip()
3127

3228

3329
What's New in Python 2.1 (final)?

Python/bltinmodule.c

Lines changed: 44 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2102,7 +2102,8 @@ builtin_zip(PyObject *self, PyObject *args)
21022102
{
21032103
PyObject *ret;
21042104
int itemsize = PySequence_Length(args);
2105-
int i, j;
2105+
int i;
2106+
PyObject *itlist; /* tuple of iterators */
21062107

21072108
if (itemsize < 1) {
21082109
PyErr_SetString(PyExc_TypeError,
@@ -2112,35 +2113,60 @@ builtin_zip(PyObject *self, PyObject *args)
21122113
/* args must be a tuple */
21132114
assert(PyTuple_Check(args));
21142115

2116+
/* allocate result list */
21152117
if ((ret = PyList_New(0)) == NULL)
21162118
return NULL;
21172119

2118-
for (i = 0;; i++) {
2119-
PyObject *next = PyTuple_New(itemsize);
2120-
if (!next) {
2121-
Py_DECREF(ret);
2122-
return NULL;
2120+
/* obtain iterators */
2121+
itlist = PyTuple_New(itemsize);
2122+
if (itlist == NULL)
2123+
goto Fail_ret;
2124+
for (i = 0; i < itemsize; ++i) {
2125+
PyObject *item = PyTuple_GET_ITEM(args, i);
2126+
PyObject *it = PyObject_GetIter(item);
2127+
if (it == NULL) {
2128+
if (PyErr_ExceptionMatches(PyExc_TypeError))
2129+
PyErr_Format(PyExc_TypeError,
2130+
"zip argument #%d must support iteration",
2131+
i+1);
2132+
goto Fail_ret_itlist;
21232133
}
2124-
for (j = 0; j < itemsize; j++) {
2125-
PyObject *seq = PyTuple_GET_ITEM(args, j);
2126-
PyObject *item = PySequence_GetItem(seq, i);
2134+
PyTuple_SET_ITEM(itlist, i, it);
2135+
}
21272136

2137+
/* build result into ret list */
2138+
for (;;) {
2139+
int status;
2140+
PyObject *next = PyTuple_New(itemsize);
2141+
if (!next)
2142+
goto Fail_ret_itlist;
2143+
2144+
for (i = 0; i < itemsize; i++) {
2145+
PyObject *it = PyTuple_GET_ITEM(itlist, i);
2146+
PyObject *item = PyIter_Next(it);
21282147
if (!item) {
2129-
if (PyErr_ExceptionMatches(PyExc_IndexError)) {
2130-
PyErr_Clear();
2131-
Py_DECREF(next);
2132-
return ret;
2148+
if (PyErr_Occurred()) {
2149+
Py_DECREF(ret);
2150+
ret = NULL;
21332151
}
21342152
Py_DECREF(next);
2135-
Py_DECREF(ret);
2136-
return NULL;
2153+
Py_DECREF(itlist);
2154+
return ret;
21372155
}
2138-
PyTuple_SET_ITEM(next, j, item);
2156+
PyTuple_SET_ITEM(next, i, item);
21392157
}
2140-
PyList_Append(ret, next);
2158+
2159+
status = PyList_Append(ret, next);
21412160
Py_DECREF(next);
2161+
if (status < 0)
2162+
goto Fail_ret_itlist;
21422163
}
2143-
/* no return */
2164+
2165+
Fail_ret_itlist:
2166+
Py_DECREF(itlist);
2167+
Fail_ret:
2168+
Py_DECREF(ret);
2169+
return NULL;
21442170
}
21452171

21462172

0 commit comments

Comments
 (0)