From 736c0ab428e69b1be67bd91969477e5227613241 Mon Sep 17 00:00:00 2001 From: Raymond Hettinger Date: Thu, 13 Mar 2008 02:09:15 +0000 Subject: [PATCH] Move itertools izip() code to builtins as zip(). Complete the renaming. --- Include/iterobject.h | 3 - Lib/filecmp.py | 6 +- Lib/heapq.py | 6 +- Lib/test/seq_tests.py | 2 +- Lib/test/test_ast.py | 4 +- Lib/test/test_heapq.py | 2 +- Lib/test/test_itertools.py | 164 ++++++++++++++-------------- Misc/NEWS | 6 +- Modules/itertoolsmodule.c | 213 +++---------------------------------- Objects/iterobject.c | 169 ----------------------------- Python/bltinmodule.c | 182 +++++++++++++++++++++++++++++-- 11 files changed, 281 insertions(+), 476 deletions(-) diff --git a/Include/iterobject.h b/Include/iterobject.h index 851cd7b646d..f61726f1f7f 100644 --- a/Include/iterobject.h +++ b/Include/iterobject.h @@ -7,7 +7,6 @@ extern "C" { PyAPI_DATA(PyTypeObject) PySeqIter_Type; PyAPI_DATA(PyTypeObject) PyCallIter_Type; -PyAPI_DATA(PyTypeObject) PyZipIter_Type; PyAPI_DATA(PyTypeObject) PyCmpWrapper_Type; #define PySeqIter_Check(op) (Py_TYPE(op) == &PySeqIter_Type) @@ -19,8 +18,6 @@ PyAPI_FUNC(PyObject *) PySeqIter_New(PyObject *); PyAPI_FUNC(PyObject *) PyCallIter_New(PyObject *, PyObject *); -PyObject* _PyZip_CreateIter(PyObject* args); - #ifdef __cplusplus } #endif diff --git a/Lib/filecmp.py b/Lib/filecmp.py index 56d557b4e3f..68a8321decb 100644 --- a/Lib/filecmp.py +++ b/Lib/filecmp.py @@ -12,7 +12,7 @@ import os import stat import warnings -from itertools import filterfalse, izip +from itertools import filterfalse __all__ = ["cmp","dircmp","cmpfiles"] @@ -130,8 +130,8 @@ def phase0(self): # Compare everything except common subdirectories self.right_list.sort() def phase1(self): # Compute common names - a = dict(izip(map(os.path.normcase, self.left_list), self.left_list)) - b = dict(izip(map(os.path.normcase, self.right_list), self.right_list)) + a = dict(zip(map(os.path.normcase, self.left_list), self.left_list)) + b = dict(zip(map(os.path.normcase, self.right_list), self.right_list)) self.common = list(map(a.__getitem__, filter(b.__contains__, a))) self.left_only = list(map(a.__getitem__, filterfalse(b.__contains__, a))) self.right_only = list(map(b.__getitem__, filterfalse(a.__contains__, b))) diff --git a/Lib/heapq.py b/Lib/heapq.py index 48697f63939..47d246ec56e 100644 --- a/Lib/heapq.py +++ b/Lib/heapq.py @@ -129,7 +129,7 @@ __all__ = ['heappush', 'heappop', 'heapify', 'heapreplace', 'merge', 'nlargest', 'nsmallest'] -from itertools import islice, repeat, count, izip, tee +from itertools import islice, repeat, count, tee from operator import itemgetter, neg import bisect @@ -352,7 +352,7 @@ def nsmallest(n, iterable, key=None): """ in1, in2 = tee(iterable) keys = in1 if key is None else map(key, in1) - it = izip(keys, count(), in2) # decorate + it = zip(keys, count(), in2) # decorate result = _nsmallest(n, it) return list(map(itemgetter(2), result)) # undecorate @@ -364,7 +364,7 @@ def nlargest(n, iterable, key=None): """ in1, in2 = tee(iterable) keys = in1 if key is None else map(key, in1) - it = izip(keys, map(neg, count()), in2) # decorate + it = zip(keys, map(neg, count()), in2) # decorate result = _nlargest(n, it) return list(map(itemgetter(2), result)) # undecorate diff --git a/Lib/test/seq_tests.py b/Lib/test/seq_tests.py index dfa18c5558a..dd12ee3a056 100644 --- a/Lib/test/seq_tests.py +++ b/Lib/test/seq_tests.py @@ -79,7 +79,7 @@ def __iter__(self): def __next__(self): raise StopIteration -from itertools import chain, map +from itertools import chain def itermulti(seqn): 'Test multiple tiers of iterators' return chain(map(lambda x:x, iterfunc(IterGen(Sequence(seqn))))) diff --git a/Lib/test/test_ast.py b/Lib/test/test_ast.py index 4883ed5f4db..68e5c88efa8 100644 --- a/Lib/test/test_ast.py +++ b/Lib/test/test_ast.py @@ -1,4 +1,4 @@ -import sys, itertools +import sys import _ast def to_tuple(t): @@ -142,7 +142,7 @@ def run_tests(): for input, output, kind in ((exec_tests, exec_results, "exec"), (single_tests, single_results, "single"), (eval_tests, eval_results, "eval")): - for i, o in itertools.izip(input, output): + for i, o in zip(input, output): ast_tree = compile(i, "?", kind, 0x400) tup = to_tuple(ast_tree) assert tup == o, ("kind=%r\ninput=%r\nexpected=%r\ngot=%r" % diff --git a/Lib/test/test_heapq.py b/Lib/test/test_heapq.py index 7969d6ec899..1e21736b7a3 100644 --- a/Lib/test/test_heapq.py +++ b/Lib/test/test_heapq.py @@ -260,7 +260,7 @@ def __iter__(self): def __next__(self): raise StopIteration -from itertools import chain, map +from itertools import chain def L(seqn): 'Test multiple tiers of iterators' return chain(map(lambda x:x, R(Ig(G(seqn))))) diff --git a/Lib/test/test_itertools.py b/Lib/test/test_itertools.py index 928f4896c08..d44235bc77f 100644 --- a/Lib/test/test_itertools.py +++ b/Lib/test/test_itertools.py @@ -8,8 +8,6 @@ from functools import reduce maxsize = test_support.MAX_Py_ssize_t minsize = -maxsize-1 -ifilter = filter -imap = map def lzip(*args): return list(zip(*args)) @@ -313,16 +311,16 @@ def keyfunc(obj): keyfunc.skip = 1 self.assertRaises(ExpectedError, gulp, [None, None], keyfunc) - def test_ifilter(self): - self.assertEqual(list(ifilter(isEven, range(6))), [0,2,4]) - self.assertEqual(list(ifilter(None, [0,1,0,2,0])), [1,2]) - self.assertEqual(list(ifilter(bool, [0,1,0,2,0])), [1,2]) - self.assertEqual(take(4, ifilter(isEven, count())), [0,2,4,6]) - self.assertRaises(TypeError, ifilter) - self.assertRaises(TypeError, ifilter, lambda x:x) - self.assertRaises(TypeError, ifilter, lambda x:x, range(6), 7) - self.assertRaises(TypeError, ifilter, isEven, 3) - self.assertRaises(TypeError, next, ifilter(range(6), range(6))) + def test_filter(self): + self.assertEqual(list(filter(isEven, range(6))), [0,2,4]) + self.assertEqual(list(filter(None, [0,1,0,2,0])), [1,2]) + self.assertEqual(list(filter(bool, [0,1,0,2,0])), [1,2]) + self.assertEqual(take(4, filter(isEven, count())), [0,2,4,6]) + self.assertRaises(TypeError, filter) + self.assertRaises(TypeError, filter, lambda x:x) + self.assertRaises(TypeError, filter, lambda x:x, range(6), 7) + self.assertRaises(TypeError, filter, isEven, 3) + self.assertRaises(TypeError, next, filter(range(6), range(6))) def test_filterfalse(self): self.assertEqual(list(filterfalse(isEven, range(6))), [1,3,5]) @@ -335,28 +333,28 @@ def test_filterfalse(self): self.assertRaises(TypeError, filterfalse, isEven, 3) self.assertRaises(TypeError, next, filterfalse(range(6), range(6))) - def test_izip(self): - # XXX This is rather silly now that builtin zip() calls izip()... - ans = [(x,y) for x, y in izip('abc',count())] + def test_zip(self): + # XXX This is rather silly now that builtin zip() calls zip()... + ans = [(x,y) for x, y in zip('abc',count())] self.assertEqual(ans, [('a', 0), ('b', 1), ('c', 2)]) - self.assertEqual(list(izip('abc', range(6))), lzip('abc', range(6))) - self.assertEqual(list(izip('abcdef', range(3))), lzip('abcdef', range(3))) - self.assertEqual(take(3,izip('abcdef', count())), lzip('abcdef', range(3))) - self.assertEqual(list(izip('abcdef')), lzip('abcdef')) - self.assertEqual(list(izip()), lzip()) - self.assertRaises(TypeError, izip, 3) - self.assertRaises(TypeError, izip, range(3), 3) + self.assertEqual(list(zip('abc', range(6))), lzip('abc', range(6))) + self.assertEqual(list(zip('abcdef', range(3))), lzip('abcdef', range(3))) + self.assertEqual(take(3,zip('abcdef', count())), lzip('abcdef', range(3))) + self.assertEqual(list(zip('abcdef')), lzip('abcdef')) + self.assertEqual(list(zip()), lzip()) + self.assertRaises(TypeError, zip, 3) + self.assertRaises(TypeError, zip, range(3), 3) # Check tuple re-use (implementation detail) - self.assertEqual([tuple(list(pair)) for pair in izip('abc', 'def')], + self.assertEqual([tuple(list(pair)) for pair in zip('abc', 'def')], lzip('abc', 'def')) - self.assertEqual([pair for pair in izip('abc', 'def')], + self.assertEqual([pair for pair in zip('abc', 'def')], lzip('abc', 'def')) - ids = list(map(id, izip('abc', 'def'))) + ids = list(map(id, zip('abc', 'def'))) self.assertEqual(min(ids), max(ids)) - ids = list(map(id, list(izip('abc', 'def')))) + ids = list(map(id, list(zip('abc', 'def')))) self.assertEqual(len(dict.fromkeys(ids)), len(ids)) - def test_iziplongest(self): + def test_ziplongest(self): for args in [ ['abc', range(6)], [range(6), 'abc'], @@ -378,7 +376,7 @@ def test_iziplongest(self): self.assertEqual(list(zip_longest('abcdef')), list(zip('abcdef'))) self.assertEqual(list(zip_longest('abc', 'defg', **{})), - list(izip(list('abc')+[None], 'defg'))) # empty keyword dict + list(zip(list('abc')+[None], 'defg'))) # empty keyword dict self.assertRaises(TypeError, zip_longest, 3) self.assertRaises(TypeError, zip_longest, range(3), 3) @@ -448,29 +446,29 @@ def test_repeat(self): list(r) self.assertEqual(repr(r), 'repeat((1+0j), 0)') - def test_imap(self): - self.assertEqual(list(imap(operator.pow, range(3), range(1,7))), + def test_map(self): + self.assertEqual(list(map(operator.pow, range(3), range(1,7))), [0**1, 1**2, 2**3]) def tupleize(*args): return args - self.assertEqual(list(imap(tupleize, 'abc', range(5))), + self.assertEqual(list(map(tupleize, 'abc', range(5))), [('a',0),('b',1),('c',2)]) - self.assertEqual(list(imap(tupleize, 'abc', count())), + self.assertEqual(list(map(tupleize, 'abc', count())), [('a',0),('b',1),('c',2)]) - self.assertEqual(take(2,imap(tupleize, 'abc', count())), + self.assertEqual(take(2,map(tupleize, 'abc', count())), [('a',0),('b',1)]) - self.assertEqual(list(imap(operator.pow, [])), []) - self.assertRaises(TypeError, imap) - self.assertRaises(TypeError, list, imap(None, range(3), range(3))) - self.assertRaises(TypeError, imap, operator.neg) - self.assertRaises(TypeError, next, imap(10, range(5))) - self.assertRaises(ValueError, next, imap(errfunc, [4], [5])) - self.assertRaises(TypeError, next, imap(onearg, [4], [5])) + self.assertEqual(list(map(operator.pow, [])), []) + self.assertRaises(TypeError, map) + self.assertRaises(TypeError, list, map(None, range(3), range(3))) + self.assertRaises(TypeError, map, operator.neg) + self.assertRaises(TypeError, next, map(10, range(5))) + self.assertRaises(ValueError, next, map(errfunc, [4], [5])) + self.assertRaises(TypeError, next, map(onearg, [4], [5])) def test_starmap(self): self.assertEqual(list(starmap(operator.pow, zip(range(3), range(1,7)))), [0**1, 1**2, 2**3]) - self.assertEqual(take(3, starmap(operator.pow, izip(count(), count(1)))), + self.assertEqual(take(3, starmap(operator.pow, zip(count(), count(1)))), [0**1, 1**2, 2**3]) self.assertEqual(list(starmap(operator.pow, [])), []) self.assertEqual(list(starmap(operator.pow, [iter([4,5])])), [4**5]) @@ -641,9 +639,9 @@ def irange(n): self.assertRaises(ReferenceError, getattr, p, '__class__') def test_StopIteration(self): - self.assertRaises(StopIteration, next, izip()) + self.assertRaises(StopIteration, next, zip()) - for f in (chain, cycle, izip, groupby): + for f in (chain, cycle, zip, groupby): self.assertRaises(StopIteration, next, f([])) self.assertRaises(StopIteration, next, f(StopNow())) @@ -659,7 +657,7 @@ def test_StopIteration(self): self.assertRaises(StopIteration, next, repeat(None, 0)) - for f in (ifilter, filterfalse, imap, takewhile, dropwhile, starmap): + for f in (filter, filterfalse, map, takewhile, dropwhile, starmap): self.assertRaises(StopIteration, next, f(lambda x:x, [])) self.assertRaises(StopIteration, next, f(lambda x:x, StopNow())) @@ -686,21 +684,21 @@ def test_groupby(self): a = [] self.makecycle(groupby([a]*2, lambda x:x), a) - def test_ifilter(self): + def test_filter(self): a = [] - self.makecycle(ifilter(lambda x:True, [a]*2), a) + self.makecycle(filter(lambda x:True, [a]*2), a) def test_filterfalse(self): a = [] self.makecycle(filterfalse(lambda x:False, a), a) - def test_izip(self): + def test_zip(self): a = [] - self.makecycle(izip([a]*2, [a]*3), a) + self.makecycle(zip([a]*2, [a]*3), a) - def test_imap(self): + def test_map(self): a = [] - self.makecycle(imap(lambda x:x, [a]*2), a) + self.makecycle(map(lambda x:x, [a]*2), a) def test_islice(self): a = [] @@ -792,7 +790,7 @@ def __next__(self): def L(seqn): 'Test multiple tiers of iterators' - return chain(imap(lambda x:x, R(Ig(G(seqn))))) + return chain(map(lambda x:x, R(Ig(G(seqn))))) class TestVariousIteratorArgs(unittest.TestCase): @@ -831,14 +829,14 @@ def test_groupby(self): self.assertRaises(TypeError, groupby, N(s)) self.assertRaises(ZeroDivisionError, list, groupby(E(s))) - def test_ifilter(self): + def test_filter(self): for s in (range(10), range(0), range(1000), (7,11), range(2000,2200,5)): for g in (G, I, Ig, S, L, R): - self.assertEqual(list(ifilter(isEven, g(s))), + self.assertEqual(list(filter(isEven, g(s))), [x for x in g(s) if isEven(x)]) - self.assertRaises(TypeError, ifilter, isEven, X(s)) - self.assertRaises(TypeError, ifilter, isEven, N(s)) - self.assertRaises(ZeroDivisionError, list, ifilter(isEven, E(s))) + self.assertRaises(TypeError, filter, isEven, X(s)) + self.assertRaises(TypeError, filter, isEven, N(s)) + self.assertRaises(ZeroDivisionError, list, filter(isEven, E(s))) def test_filterfalse(self): for s in (range(10), range(0), range(1000), (7,11), range(2000,2200,5)): @@ -849,16 +847,16 @@ def test_filterfalse(self): self.assertRaises(TypeError, filterfalse, isEven, N(s)) self.assertRaises(ZeroDivisionError, list, filterfalse(isEven, E(s))) - def test_izip(self): + def test_zip(self): for s in ("123", "", range(1000), ('do', 1.2), range(2000,2200,5)): for g in (G, I, Ig, S, L, R): - self.assertEqual(list(izip(g(s))), lzip(g(s))) - self.assertEqual(list(izip(g(s), g(s))), lzip(g(s), g(s))) - self.assertRaises(TypeError, izip, X(s)) - self.assertRaises(TypeError, izip, N(s)) - self.assertRaises(ZeroDivisionError, list, izip(E(s))) + self.assertEqual(list(zip(g(s))), lzip(g(s))) + self.assertEqual(list(zip(g(s), g(s))), lzip(g(s), g(s))) + self.assertRaises(TypeError, zip, X(s)) + self.assertRaises(TypeError, zip, N(s)) + self.assertRaises(ZeroDivisionError, list, zip(E(s))) - def test_iziplongest(self): + def test_ziplongest(self): for s in ("123", "", range(1000), ('do', 1.2), range(2000,2200,5)): for g in (G, I, Ig, S, L, R): self.assertEqual(list(zip_longest(g(s))), list(zip(g(s)))) @@ -867,16 +865,16 @@ def test_iziplongest(self): self.assertRaises(TypeError, zip_longest, N(s)) self.assertRaises(ZeroDivisionError, list, zip_longest(E(s))) - def test_imap(self): + def test_map(self): for s in (range(10), range(0), range(100), (7,11), range(20,50,5)): for g in (G, I, Ig, S, L, R): - self.assertEqual(list(imap(onearg, g(s))), + self.assertEqual(list(map(onearg, g(s))), [onearg(x) for x in g(s)]) - self.assertEqual(list(imap(operator.pow, g(s), g(s))), + self.assertEqual(list(map(operator.pow, g(s), g(s))), [x**x for x in g(s)]) - self.assertRaises(TypeError, imap, onearg, X(s)) - self.assertRaises(TypeError, imap, onearg, N(s)) - self.assertRaises(ZeroDivisionError, list, imap(onearg, E(s))) + self.assertRaises(TypeError, map, onearg, X(s)) + self.assertRaises(TypeError, map, onearg, N(s)) + self.assertRaises(ZeroDivisionError, list, map(onearg, E(s))) def test_islice(self): for s in ("12345", "", range(1000), ('do', 1.2), range(2000,2200,5)): @@ -953,8 +951,8 @@ def g(value, first=[1]): return value items = list(tuple2) items[1:1] = list(tuple1) - gen = imap(g, items) - z = izip(*[gen]*len(tuple1)) + gen = map(g, items) + z = zip(*[gen]*len(tuple1)) next(z) def f(t): @@ -1001,7 +999,7 @@ def gen2(x): class SubclassWithKwargsTest(unittest.TestCase): def test_keywords_in_subclass(self): # count is not subclassable... - for cls in (repeat, izip, ifilter, filterfalse, chain, imap, + for cls in (repeat, zip, filter, filterfalse, chain, map, starmap, islice, takewhile, dropwhile, cycle): class Subclass(cls): def __init__(self, newarg=None, *args): @@ -1017,7 +1015,7 @@ def __init__(self, newarg=None, *args): >>> amounts = [120.15, 764.05, 823.14] ->>> for checknum, amount in izip(count(1200), amounts): +>>> for checknum, amount in zip(count(1200), amounts): ... print('Check %d is for $%.2f' % (checknum, amount)) ... Check 1200 is for $120.15 @@ -1025,7 +1023,7 @@ def __init__(self, newarg=None, *args): Check 1202 is for $823.14 >>> import operator ->>> for cube in imap(operator.pow, range(1,4), repeat(3)): +>>> for cube in map(operator.pow, range(1,4), repeat(3)): ... print(cube) ... 1 @@ -1070,14 +1068,14 @@ def __init__(self, newarg=None, *args): ... return list(islice(seq, n)) >>> def enumerate(iterable): -... return izip(count(), iterable) +... return zip(count(), iterable) >>> def tabulate(function): ... "Return function(0), function(1), ..." -... return imap(function, count()) +... return map(function, count()) >>> def iteritems(mapping): -... return izip(mapping.keys(), mapping.values()) +... return zip(mapping.keys(), mapping.values()) >>> def nth(iterable, n): ... "Returns the nth item" @@ -1091,19 +1089,19 @@ def __init__(self, newarg=None, *args): >>> def any(seq, pred=None): ... "Returns True if pred(x) is true for at least one element in the iterable" -... for elem in ifilter(pred, seq): +... for elem in filter(pred, seq): ... return True ... return False >>> def no(seq, pred=None): ... "Returns True if pred(x) is false for every element in the iterable" -... for elem in ifilter(pred, seq): +... for elem in filter(pred, seq): ... return False ... return True >>> def quantify(seq, pred=None): ... "Count how many times the predicate is true in the sequence" -... return sum(imap(pred, seq)) +... return sum(map(pred, seq)) >>> def padnone(seq): ... "Returns the sequence elements and then returns None indefinitely" @@ -1114,7 +1112,7 @@ def __init__(self, newarg=None, *args): ... return chain(*repeat(seq, n)) >>> def dotproduct(vec1, vec2): -... return sum(imap(operator.mul, vec1, vec2)) +... return sum(map(operator.mul, vec1, vec2)) >>> def flatten(listOfLists): ... return list(chain(*listOfLists)) @@ -1134,7 +1132,7 @@ def __init__(self, newarg=None, *args): ... next(b) ... except StopIteration: ... pass -... return izip(a, b) +... return zip(a, b) This is not part of the examples but it tests to make sure the definitions perform as purported. @@ -1180,7 +1178,7 @@ def __init__(self, newarg=None, *args): [8, 8, 8, 8, 8] >>> import random ->>> take(5, imap(int, repeatfunc(random.random))) +>>> take(5, map(int, repeatfunc(random.random))) [0, 0, 0, 0, 0] >>> list(pairwise('abcd')) diff --git a/Misc/NEWS b/Misc/NEWS index 84b3d3a97ed..b654516113b 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -72,7 +72,7 @@ Core and Builtins - Issue #1969: split and rsplit in bytearray are inconsistent -- map() and itertools.imap() no longer accept None for the first argument. +- map() and no longer accepts None for the first argument. Use zip() instead. - Issue #1769: Now int("- 1") is not allowed any more. @@ -123,6 +123,10 @@ Core and Builtins Extension Modules ----------------- +- Code for itertools ifilter(), imap(), and izip() moved to bultins and + renamed to filter(), map(), and zip(). Also, renamed izip_longest() + to zip_longest() and ifilterfalse() to filterfalse(). + - Issue #1762972: Readded the reload() function as imp.reload() - Bug #2111: mmap segfaults when trying to write a block opened with PROT_READ diff --git a/Modules/itertoolsmodule.c b/Modules/itertoolsmodule.c index 283d8483d63..b52bea84136 100644 --- a/Modules/itertoolsmodule.c +++ b/Modules/itertoolsmodule.c @@ -2352,193 +2352,6 @@ static PyTypeObject count_type = { }; -/* izip object ************************************************************/ - -#include "Python.h" - -typedef struct { - PyObject_HEAD - Py_ssize_t tuplesize; - PyObject *ittuple; /* tuple of iterators */ - PyObject *result; -} izipobject; - -static PyTypeObject izip_type; - -static PyObject * -izip_new(PyTypeObject *type, PyObject *args, PyObject *kwds) -{ - izipobject *lz; - Py_ssize_t i; - PyObject *ittuple; /* tuple of iterators */ - PyObject *result; - Py_ssize_t tuplesize = PySequence_Length(args); - - if (type == &izip_type && !_PyArg_NoKeywords("izip()", kwds)) - return NULL; - - /* args must be a tuple */ - assert(PyTuple_Check(args)); - - /* obtain iterators */ - ittuple = PyTuple_New(tuplesize); - if (ittuple == NULL) - return NULL; - for (i=0; i < tuplesize; ++i) { - PyObject *item = PyTuple_GET_ITEM(args, i); - PyObject *it = PyObject_GetIter(item); - if (it == NULL) { - if (PyErr_ExceptionMatches(PyExc_TypeError)) - PyErr_Format(PyExc_TypeError, - "izip argument #%zd must support iteration", - i+1); - Py_DECREF(ittuple); - return NULL; - } - PyTuple_SET_ITEM(ittuple, i, it); - } - - /* create a result holder */ - result = PyTuple_New(tuplesize); - if (result == NULL) { - Py_DECREF(ittuple); - return NULL; - } - for (i=0 ; i < tuplesize ; i++) { - Py_INCREF(Py_None); - PyTuple_SET_ITEM(result, i, Py_None); - } - - /* create izipobject structure */ - lz = (izipobject *)type->tp_alloc(type, 0); - if (lz == NULL) { - Py_DECREF(ittuple); - Py_DECREF(result); - return NULL; - } - lz->ittuple = ittuple; - lz->tuplesize = tuplesize; - lz->result = result; - - return (PyObject *)lz; -} - -static void -izip_dealloc(izipobject *lz) -{ - PyObject_GC_UnTrack(lz); - Py_XDECREF(lz->ittuple); - Py_XDECREF(lz->result); - Py_TYPE(lz)->tp_free(lz); -} - -static int -izip_traverse(izipobject *lz, visitproc visit, void *arg) -{ - Py_VISIT(lz->ittuple); - Py_VISIT(lz->result); - return 0; -} - -static PyObject * -izip_next(izipobject *lz) -{ - Py_ssize_t i; - Py_ssize_t tuplesize = lz->tuplesize; - PyObject *result = lz->result; - PyObject *it; - PyObject *item; - PyObject *olditem; - - if (tuplesize == 0) - return NULL; - if (Py_REFCNT(result) == 1) { - Py_INCREF(result); - for (i=0 ; i < tuplesize ; i++) { - it = PyTuple_GET_ITEM(lz->ittuple, i); - assert(PyIter_Check(it)); - item = (*Py_TYPE(it)->tp_iternext)(it); - if (item == NULL) { - Py_DECREF(result); - return NULL; - } - olditem = PyTuple_GET_ITEM(result, i); - PyTuple_SET_ITEM(result, i, item); - Py_DECREF(olditem); - } - } else { - result = PyTuple_New(tuplesize); - if (result == NULL) - return NULL; - for (i=0 ; i < tuplesize ; i++) { - it = PyTuple_GET_ITEM(lz->ittuple, i); - assert(PyIter_Check(it)); - item = (*Py_TYPE(it)->tp_iternext)(it); - if (item == NULL) { - Py_DECREF(result); - return NULL; - } - PyTuple_SET_ITEM(result, i, item); - } - } - return result; -} - -PyDoc_STRVAR(izip_doc, -"izip(iter1 [,iter2 [...]]) --> izip object\n\ -\n\ -Return a izip object whose .__next__() method returns a tuple where\n\ -the i-th element comes from the i-th iterable argument. The .__next__()\n\ -method continues until the shortest iterable in the argument sequence\n\ -is exhausted and then it raises StopIteration. Works like the zip()\n\ -function but consumes less memory by returning an iterator instead of\n\ -a list."); - -static PyTypeObject izip_type = { - PyVarObject_HEAD_INIT(NULL, 0) - "itertools.izip", /* tp_name */ - sizeof(izipobject), /* tp_basicsize */ - 0, /* tp_itemsize */ - /* methods */ - (destructor)izip_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - PyObject_GenericGetAttr, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | - Py_TPFLAGS_BASETYPE, /* tp_flags */ - izip_doc, /* tp_doc */ - (traverseproc)izip_traverse, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - PyObject_SelfIter, /* tp_iter */ - (iternextfunc)izip_next, /* tp_iternext */ - 0, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - 0, /* tp_init */ - 0, /* tp_alloc */ - izip_new, /* tp_new */ - PyObject_GC_Del, /* tp_free */ -}; - - /* repeat object ************************************************************/ typedef struct { @@ -2675,7 +2488,7 @@ static PyTypeObject repeat_type = { PyObject_GC_Del, /* tp_free */ }; -/* iziplongest object ************************************************************/ +/* ziplongest object ************************************************************/ #include "Python.h" @@ -2686,14 +2499,14 @@ typedef struct { PyObject *ittuple; /* tuple of iterators */ PyObject *result; PyObject *fillvalue; -} iziplongestobject; +} ziplongestobject; -static PyTypeObject iziplongest_type; +static PyTypeObject ziplongest_type; static PyObject * zip_longest_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { - iziplongestobject *lz; + ziplongestobject *lz; Py_ssize_t i; PyObject *ittuple; /* tuple of iterators */ PyObject *result; @@ -2741,8 +2554,8 @@ zip_longest_new(PyTypeObject *type, PyObject *args, PyObject *kwds) PyTuple_SET_ITEM(result, i, Py_None); } - /* create iziplongestobject structure */ - lz = (iziplongestobject *)type->tp_alloc(type, 0); + /* create ziplongestobject structure */ + lz = (ziplongestobject *)type->tp_alloc(type, 0); if (lz == NULL) { Py_DECREF(ittuple); Py_DECREF(result); @@ -2758,7 +2571,7 @@ zip_longest_new(PyTypeObject *type, PyObject *args, PyObject *kwds) } static void -zip_longest_dealloc(iziplongestobject *lz) +zip_longest_dealloc(ziplongestobject *lz) { PyObject_GC_UnTrack(lz); Py_XDECREF(lz->ittuple); @@ -2768,7 +2581,7 @@ zip_longest_dealloc(iziplongestobject *lz) } static int -zip_longest_traverse(iziplongestobject *lz, visitproc visit, void *arg) +zip_longest_traverse(ziplongestobject *lz, visitproc visit, void *arg) { Py_VISIT(lz->ittuple); Py_VISIT(lz->result); @@ -2777,7 +2590,7 @@ zip_longest_traverse(iziplongestobject *lz, visitproc visit, void *arg) } static PyObject * -zip_longest_next(iziplongestobject *lz) +zip_longest_next(ziplongestobject *lz) { Py_ssize_t i; Py_ssize_t tuplesize = lz->tuplesize; @@ -2859,10 +2672,10 @@ are exhausted, the fillvalue is substituted in their place. The fillvalue\n\ defaults to None or can be specified by a keyword argument.\n\ "); -static PyTypeObject iziplongest_type = { +static PyTypeObject ziplongest_type = { PyVarObject_HEAD_INIT(NULL, 0) "itertools.zip_longest", /* tp_name */ - sizeof(iziplongestobject), /* tp_basicsize */ + sizeof(ziplongestobject), /* tp_basicsize */ 0, /* tp_itemsize */ /* methods */ (destructor)zip_longest_dealloc, /* tp_dealloc */ @@ -2914,7 +2727,6 @@ cycle(p) --> p0, p1, ... plast, p0, p1, ...\n\ repeat(elem [,n]) --> elem, elem, elem, ... endlessly or up to n times\n\ \n\ Iterators terminating on the shortest input sequence:\n\ -izip(p, q, ...) --> (p[0], q[0]), (p[1], q[1]), ... \n\ zip_longest(p, q, ...) --> (p[0], q[0]), (p[1], q[1]), ... \n\ filterfalse(pred, seq) --> elements of seq where pred(elem) is False\n\ islice(seq, [start,] stop [, step]) --> elements from\n\ @@ -2949,8 +2761,7 @@ inititertools(void) &chain_type, &filterfalse_type, &count_type, - &izip_type, - &iziplongest_type, + &ziplongest_type, &product_type, &repeat_type, &groupby_type, diff --git a/Objects/iterobject.c b/Objects/iterobject.c index 454c405926a..95ee56d039a 100644 --- a/Objects/iterobject.c +++ b/Objects/iterobject.c @@ -230,172 +230,3 @@ PyTypeObject PyCallIter_Type = { }; -/*********************** Zip Iterator **************************/ -/* Largely copied from itertools.c by Brian Holmes */ - -typedef struct zipiterobject_t { - PyObject_HEAD - PyTupleObject *it_tuple; /* Set to NULL when iterator is exhausted */ - Py_ssize_t resultsize; - PyTupleObject *result; /* Reusable tuple for optimization */ -} zipiterobject; - - /* Forward */ - -PyObject * -_PyZip_CreateIter(PyObject* args) -{ - Py_ssize_t i; - Py_ssize_t tuplesize; - PyObject* ziptuple; - PyObject* result; - struct zipiterobject_t* zipiter; - - assert(PyTuple_Check(args)); - - if (Py_TYPE(&PyZipIter_Type) == NULL) { - if (PyType_Ready(&PyZipIter_Type) < 0) - return NULL; - } - - tuplesize = PySequence_Length((PyObject*) args); - - ziptuple = PyTuple_New(tuplesize); - if (ziptuple == NULL) - return NULL; - - for (i = 0; i < tuplesize; i++) { - PyObject *o = PyTuple_GET_ITEM(args, i); - PyObject *it = PyObject_GetIter(o); - if (it == NULL) { - /* XXX Should we do this? - if (PyErr_ExceptionMatches(PyExc_TypeError)) - PyErr_Format(PyExc_TypeError, - "zip argument #%zd must support iteration", - I+1); - */ - Py_DECREF(ziptuple); - return NULL; - } - PyTuple_SET_ITEM(ziptuple, i, it); - } - - /* create a reusable result holder */ - result = PyTuple_New(tuplesize); - if (result == NULL) { - Py_DECREF(ziptuple); - return NULL; - } - for (i = 0; i < tuplesize; i++) { - Py_INCREF(Py_None); - PyTuple_SET_ITEM(result, i, Py_None); - } - - zipiter = PyObject_GC_New(zipiterobject, &PyZipIter_Type); - if (zipiter == NULL) { - Py_DECREF(ziptuple); - Py_DECREF(result); - return NULL; - } - - zipiter->result = (PyTupleObject*) result; - zipiter->resultsize = tuplesize; - zipiter->it_tuple = (PyTupleObject *) ziptuple; - _PyObject_GC_TRACK(zipiter); - return (PyObject *)zipiter; -} - -static void -zipiter_dealloc(zipiterobject *it) -{ - _PyObject_GC_UNTRACK(it); - Py_XDECREF(it->it_tuple); - Py_XDECREF(it->result); - PyObject_GC_Del(it); -} - -static int -zipiter_traverse(zipiterobject *it, visitproc visit, void *arg) -{ - Py_VISIT(it->it_tuple); - Py_VISIT(it->result); - return 0; -} - -static PyObject * -zipiter_next(zipiterobject *zit) -{ - Py_ssize_t i; - Py_ssize_t tuplesize = zit->resultsize; - PyObject *result = (PyObject*) zit->result; - PyObject *olditem; - - if (tuplesize == 0) - return NULL; - - if (result->ob_refcnt == 1) { - Py_INCREF(result); - for (i = 0; i < tuplesize; i++) { - PyObject *it = PyTuple_GET_ITEM(zit->it_tuple, i); - PyObject *item; - assert(PyIter_Check(it)); - item = (*it->ob_type->tp_iternext)(it); - if (item == NULL) { - Py_DECREF(result); - return NULL; - } - olditem = PyTuple_GET_ITEM(result, i); - PyTuple_SET_ITEM(result, i, item); - Py_DECREF(olditem); - } - } else { - result = PyTuple_New(tuplesize); - if (result == NULL) - return NULL; - for (i = 0; i < tuplesize; i++) { - PyObject *it = PyTuple_GET_ITEM(zit->it_tuple, i); - PyObject *item; - assert(PyIter_Check(it)); - item = (*it->ob_type->tp_iternext)(it); - if (item == NULL) { - Py_DECREF(result); - return NULL; - } - PyTuple_SET_ITEM(result, i, item); - } - } - return result; -} - -PyTypeObject PyZipIter_Type = { - PyVarObject_HEAD_INIT(0, 0) - "zip_iterator", /* tp_name */ - sizeof(zipiterobject), /* tp_basicsize */ - 0, /* tp_itemsize */ - /* methods */ - (destructor)zipiter_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - PyObject_GenericGetAttr, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */ - 0, /* tp_doc */ - (traverseproc)zipiter_traverse, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weakzipoffset */ - PyObject_SelfIter, /* tp_iter */ - (iternextfunc)zipiter_next, /* tp_iternext */ - 0, /* tp_methods */ - 0, /* tp_members */ -}; diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c index 024729e18a9..b3d8b160e48 100644 --- a/Python/bltinmodule.c +++ b/Python/bltinmodule.c @@ -1967,23 +1967,187 @@ When using a tuple as the second argument issubclass(X, (A, B, ...)),\n\ is a shortcut for issubclass(X, A) or issubclass(X, B) or ... (etc.)."); -static PyObject* -builtin_zip(PyObject *self, PyObject *args) +typedef struct { + PyObject_HEAD + Py_ssize_t tuplesize; + PyObject *ittuple; /* tuple of iterators */ + PyObject *result; +} zipobject; + +PyTypeObject PyZip_Type; + +static PyObject * +zip_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { + zipobject *lz; + Py_ssize_t i; + PyObject *ittuple; /* tuple of iterators */ + PyObject *result; + Py_ssize_t tuplesize = PySequence_Length(args); + + if (type == &PyZip_Type && !_PyArg_NoKeywords("zip()", kwds)) + return NULL; + /* args must be a tuple */ assert(PyTuple_Check(args)); - return _PyZip_CreateIter(args); + /* obtain iterators */ + ittuple = PyTuple_New(tuplesize); + if (ittuple == NULL) + return NULL; + for (i=0; i < tuplesize; ++i) { + PyObject *item = PyTuple_GET_ITEM(args, i); + PyObject *it = PyObject_GetIter(item); + if (it == NULL) { + if (PyErr_ExceptionMatches(PyExc_TypeError)) + PyErr_Format(PyExc_TypeError, + "zip argument #%zd must support iteration", + i+1); + Py_DECREF(ittuple); + return NULL; + } + PyTuple_SET_ITEM(ittuple, i, it); + } + + /* create a result holder */ + result = PyTuple_New(tuplesize); + if (result == NULL) { + Py_DECREF(ittuple); + return NULL; + } + for (i=0 ; i < tuplesize ; i++) { + Py_INCREF(Py_None); + PyTuple_SET_ITEM(result, i, Py_None); + } + + /* create zipobject structure */ + lz = (zipobject *)type->tp_alloc(type, 0); + if (lz == NULL) { + Py_DECREF(ittuple); + Py_DECREF(result); + return NULL; + } + lz->ittuple = ittuple; + lz->tuplesize = tuplesize; + lz->result = result; + + return (PyObject *)lz; } +static void +zip_dealloc(zipobject *lz) +{ + PyObject_GC_UnTrack(lz); + Py_XDECREF(lz->ittuple); + Py_XDECREF(lz->result); + Py_TYPE(lz)->tp_free(lz); +} + +static int +zip_traverse(zipobject *lz, visitproc visit, void *arg) +{ + Py_VISIT(lz->ittuple); + Py_VISIT(lz->result); + return 0; +} + +static PyObject * +zip_next(zipobject *lz) +{ + Py_ssize_t i; + Py_ssize_t tuplesize = lz->tuplesize; + PyObject *result = lz->result; + PyObject *it; + PyObject *item; + PyObject *olditem; + + if (tuplesize == 0) + return NULL; + if (Py_REFCNT(result) == 1) { + Py_INCREF(result); + for (i=0 ; i < tuplesize ; i++) { + it = PyTuple_GET_ITEM(lz->ittuple, i); + assert(PyIter_Check(it)); + item = (*Py_TYPE(it)->tp_iternext)(it); + if (item == NULL) { + Py_DECREF(result); + return NULL; + } + olditem = PyTuple_GET_ITEM(result, i); + PyTuple_SET_ITEM(result, i, item); + Py_DECREF(olditem); + } + } else { + result = PyTuple_New(tuplesize); + if (result == NULL) + return NULL; + for (i=0 ; i < tuplesize ; i++) { + it = PyTuple_GET_ITEM(lz->ittuple, i); + assert(PyIter_Check(it)); + item = (*Py_TYPE(it)->tp_iternext)(it); + if (item == NULL) { + Py_DECREF(result); + return NULL; + } + PyTuple_SET_ITEM(result, i, item); + } + } + return result; +} PyDoc_STRVAR(zip_doc, -"zip(it1 [, it2 [...]]) -> iter([(it1[0], it2[0] ...), ...])\n\ +"zip(iter1 [,iter2 [...]]) --> zip object\n\ \n\ -Return an iterator yielding tuples, where each tuple contains the\n\ -corresponding element from each of the argument iterables.\n\ -The returned iterator ends when the shortest argument iterable is exhausted.\n\ -(This is identical to itertools.izip().)"); +Return a zip object whose .__next__() method returns a tuple where\n\ +the i-th element comes from the i-th iterable argument. The .__next__()\n\ +method continues until the shortest iterable in the argument sequence\n\ +is exhausted and then it raises StopIteration. Works like the zip()\n\ +function but consumes less memory by returning an iterator instead of\n\ +a list."); + +PyTypeObject PyZip_Type = { + PyVarObject_HEAD_INIT(&PyType_Type, 0) + "zip", /* tp_name */ + sizeof(zipobject), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + (destructor)zip_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | + Py_TPFLAGS_BASETYPE, /* tp_flags */ + zip_doc, /* tp_doc */ + (traverseproc)zip_traverse, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + PyObject_SelfIter, /* tp_iter */ + (iternextfunc)zip_next, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + PyType_GenericAlloc, /* tp_alloc */ + zip_new, /* tp_new */ + PyObject_GC_Del, /* tp_free */ +}; static PyMethodDef builtin_methods[] = { @@ -2028,7 +2192,6 @@ static PyMethodDef builtin_methods[] = { {"sorted", (PyCFunction)builtin_sorted, METH_VARARGS | METH_KEYWORDS, sorted_doc}, {"sum", builtin_sum, METH_VARARGS, sum_doc}, {"vars", builtin_vars, METH_VARARGS, vars_doc}, - {"zip", builtin_zip, METH_VARARGS, zip_doc}, {NULL, NULL}, }; @@ -2097,6 +2260,7 @@ _PyBuiltin_Init(void) SETBUILTIN("super", &PySuper_Type); SETBUILTIN("tuple", &PyTuple_Type); SETBUILTIN("type", &PyType_Type); + SETBUILTIN("zip", &PyZip_Type); debug = PyBool_FromLong(Py_OptimizeFlag == 0); if (PyDict_SetItemString(dict, "__debug__", debug) < 0) { Py_XDECREF(debug);