[Python-checkins] CVS: python/nondist/peps pep-0201.txt,1.7,1.8
Barry Warsaw
python-dev@python.org
Thu, 27 Jul 2000 12:15:22 -0700
Update of /cvsroot/python/python/nondist/peps
In directory slayer.i.sourceforge.net:/tmp/cvs-serv4670
Modified Files:
pep-0201.txt
Log Message:
Updated based on Guido's recent pronouncements on the Open Issues.
There are now no more open issues.
Index: pep-0201.txt
===================================================================
RCS file: /cvsroot/python/python/nondist/peps/pep-0201.txt,v
retrieving revision 1.7
retrieving revision 1.8
diff -C2 -r1.7 -r1.8
*** pep-0201.txt 2000/07/26 04:22:03 1.7
--- pep-0201.txt 2000/07/27 19:15:20 1.8
***************
*** 85,115 ****
function is to be called `zip' and has the following signature:
! zip(seqa, [seqb, [...]], [pad=<value>])
zip() takes one or more sequences and weaves their elements
together, just as map(None, ...) does with sequences of equal
! length. The optional keyword argument `pad', if supplied, is a
! value used to pad all shorter sequences to the length of the
! longest sequence. If `pad' is omitted, then weaving stops when
! the shortest sequence is exhausted.
!
! It is not possible to pad short lists with different pad values,
! nor will zip() ever raise an exception with lists of different
! lengths. To accomplish either behavior, the sequences must be
! checked and processed before the call to zip() -- but see the Open
! Issues below for more discussion.
!
!
! Lazy Execution
!
! For performance purposes, zip() does not construct the list of
! tuples immediately. Instead it instantiates an object that
! implements a __getitem__() method and conforms to the informal
! for-loop protocol. This method constructs the individual tuples
! on demand.
- Guido is strongly opposed to lazy execution. See Open Issues.
Examples
--- 85,101 ----
function is to be called `zip' and has the following signature:
! zip(seqa, [seqb, [...]])
zip() takes one or more sequences and weaves their elements
together, just as map(None, ...) does with sequences of equal
! length. The weaving stops when the shortest sequence is
! exhausted.
+ Return Value
+ zip() returns a real Python list, the same way map() does.
+
+
Examples
***************
*** 128,148 ****
[(1, 12), (2, 13)]
- >>> zip(a, d, pad=0)
- [(1, 12), (2, 13), (3, 0), (4, 0)]
-
- >>> zip(a, d, pid=0)
- Traceback (most recent call last):
- File "<stdin>", line 1, in ?
- File "/usr/tmp/python-iKAOxR", line 11, in zip
- TypeError: unexpected keyword arguments
-
>>> zip(a, b, c, d)
[(1, 5, 9, 12), (2, 6, 10, 13)]
- >>> zip(a, b, c, d, pad=None)
- [(1, 5, 9, 12), (2, 6, 10, 13), (3, 7, 11, None), (4, 8, None, None)]
- >>> map(None, a, b, c, d)
- [(1, 5, 9, 12), (2, 6, 10, 13), (3, 7, 11, None), (4, 8, None, None)]
-
Note that when the sequences are of the same length, zip() is
reversible:
--- 114,120 ----
***************
*** 172,404 ****
replaced by equivalent C code.
! class _Zipper:
! def __init__(self, args, kws):
! # Defaults
! self.__padgiven = 0
! if kws.has_key('pad'):
! self.__padgiven = 1
! self.__pad = kws['pad']
! del kws['pad']
! # Assert no unknown arguments are left
! if kws:
! raise TypeError('unexpected keyword arguments')
! self.__sequences = args
! self.__seqlen = len(args)
!
! def __getitem__(self, i):
! if not self.__sequences:
! raise IndexError
! ret = []
! exhausted = 0
! for s in self.__sequences:
! try:
! ret.append(s[i])
! except IndexError:
! if not self.__padgiven:
! raise
! exhausted = exhausted + 1
! if exhausted == self.__seqlen:
! raise
! ret.append(self.__pad)
! return tuple(ret)
!
! def __len__(self):
! # If we're padding, then len is the length of the longest sequence,
! # otherwise it's the length of the shortest sequence.
! if not self.__padgiven:
! shortest = -1
! for s in self.__sequences:
! slen = len(s)
! if shortest < 0 or slen < shortest:
! shortest = slen
! if shortest < 0:
! return 0
! return shortest
! longest = 0
! for s in self.__sequences:
! slen = len(s)
! if slen > longest:
! longest = slen
! return longest
!
! def __cmp__(self, other):
! i = 0
! smore = 1
! omore = 1
! while 1:
! try:
! si = self[i]
! except IndexError:
! smore = 0
! try:
! oi = other[i]
! except IndexError:
! omore = 0
! if not smore and not omore:
! return 0
! elif not smore:
! return -1
! elif not omore:
! return 1
! test = cmp(si, oi)
! if test:
! return test
! i = i + 1
!
! def __str__(self):
! ret = []
! i = 0
! while 1:
! try:
! ret.append(self[i])
! except IndexError:
! break
! i = i + 1
! return str(ret)
! __repr__ = __str__
!
!
! def zip(*args, **kws):
! return _Zipper(args, kws)
!
!
! Rejected Elaborations
!
! Some people have suggested that the user be able to specify the
! type of the inner and outer containers for the zipped sequence.
! This would be specified by additional keyword arguments to zip(),
! named `inner' and `outer'.
!
! This elaboration is rejected for several reasons. First, there
! really is no outer container, even though there appears to be an
! outer list container the example above. This is simply an
! artifact of the repr() of the zipped object. User code can do its
! own looping over the zipped object via __getitem__(), and build
! any type of outer container for the fully evaluated, concrete
! sequence. For example, to build a zipped object with lists as an
! outer container, use
!
! >>> list(zip(sequence_a, sequence_b, sequence_c))
!
! for tuple outer container, use
!
! >>> tuple(zip(sequence_a, sequence_b, sequence_c))
!
! This type of construction will usually not be necessary though,
! since it is expected that zipped objects will most often appear in
! for-loops.
!
! Second, allowing the user to specify the inner container
! introduces needless complexity and arbitrary decisions. You might
! imagine that instead of the default tuple inner container, the
! user could prefer a list, or a dictionary, or instances of some
! sequence-like class.
!
! One problem is the API. Should the argument to `inner' be a type
! or a template object? For flexibility, the argument should
! probably be a type object (i.e. TupleType, ListType, DictType), or
! a class. For classes, the implementation could just pass the zip
! element to the constructor. But what about built-in types that
! don't have constructors? They would have to be special-cased in
! the implementation (i.e. what is the constructor for TupleType?
! The tuple() built-in).
!
! Another problem that arises is for zips greater than length two.
! Say you had three sequences and you wanted the inner type to be a
! dictionary. What would the semantics of the following be?
!
! >>> zip(sequence_a, sequence_b, sequence_c, inner=DictType)
!
! Would the key be (element_a, element_b) and the value be
! element_c, or would the key be element_a and the value be
! (element_b, element_c)? Or should an exception be thrown?
!
! This suggests that the specification of the inner container type
! is needless complexity. It isn't likely that the inner container
! will need to be specified very often, and it is easy to roll your
! own should you need it. Tuples are chosen for the inner container
! type due to their (slight) memory footprint and performance
! advantages.
!
!
! Open Issues
!
! - Guido opposes lazy evaluation for zip(). He believes zip()
! should return a real list, with an xzip() lazy evaluator added
! later if necessary.
!
! - What should "zip(a)" do? Given
!
! a = (1, 2, 3); zip(a)
!
! three outcomes are possible.
!
! 1) Returns [(1,), (2,), (3,)]
!
! Pros: no special casing in the implementation or in user
! code, and is more consistent with the description of it's
! semantics. Cons: this isn't what map(None, a) would return,
! and may be counter to user expectations.
!
! 2) Returns [1, 2, 3]
!
! Pros: consistency with map(None, a), and simpler code for
! for-loops, e.g.
!
! for i in zip(a):
!
! instead of
!
! for (i,) in zip(a):
!
! Cons: too much complexity and special casing for what should
! be a relatively rare usage pattern.
!
! 3) Raises TypeError
!
! Pros: zip(a) doesn't make much sense and could be confusing
! to explain.
!
! Cons: needless restriction
!
! Current scoring seems to generally favor outcome 1.
!
! - What should "zip()" do?
!
! Along similar lines, zip() with no arguments (or zip() with just
! a pad argument) can have ambiguous semantics. Should this
! return no elements or an infinite number? For these reaons,
! raising a TypeError exception in this case makes the most
! sense.
!
! - The name of the built-in `zip' may cause some initial confusion
! with the zip compression algorithm. Other suggestions include
! (but are not limited to!): marry, weave, parallel, lace, braid,
! interlace, permute, furl, tuples, lists, stitch, collate, knit,
! plait, fold, with, mktuples, maketuples, totuples, gentuples,
! tupleorama.
!
! All have disadvantages, and there is no clear unanimous choice,
! therefore the decision was made to go with `zip' because the
! same functionality is available in other languages
! (e.g. Haskell) under the name `zip'[2].
!
! - Should zip() be including in the builtins module or should it be
! in a separate generators module (possibly with other candidate
! functions like irange())?
!
! - Padding short sequences with different values. A suggestion has
! been made to allow a `padtuple' (probably better called `pads'
! or `padseq') argument similar to `pad'. This sequence must have
! a length equal to the number of sequences given. It is a
! sequence of the individual pad values to use for each sequence,
! should it be shorter than the maximum length.
!
! One problem is what to do if `padtuple' itself isn't of the
! right length? A TypeError seems to be the only choice here.
!
! How does `pad' and `padtuple' interact? Perhaps if padtuple
! were too short, it could use pad as a fallback. padtuple would
! always override pad if both were given.
--- 144,201 ----
replaced by equivalent C code.
! def zip(*args):
! if not args:
! raise TypeError('zip() expects one or more sequence arguments')
! ret = []
! # find the length of the shortest sequence
! shortest = min(*map(len, args))
! for i in range(shortest):
! item = []
! for s in args:
! item.append(s[i])
! ret.append(tuple(item))
! return ret
!
!
! BDFL Pronouncements
!
! Note: the BDFL refers to Guido van Rossum, Python's Benevolent
! Dictator For Life.
!
! - The function's name. An earlier version of this PEP included an
! open issue listing 20+ proposed alternative names to zip(). In
! the face of no overwhelmingly better choice, the BDFL strongly
! prefers zip() due to it's Haskell[2] heritage. See version 1.7
! of this PEP for the list of alteratives.
!
! - zip() shall be a built-in function.
!
! - Optional padding. An earlier version of this PEP proposed an
! optional `pad' keyword argument, which would be used when the
! argument sequences were not the same length. This is similar
! behavior to the map(None, ...) semantics except that the user
! would be able to specify pad object. This has been rejected by
! the BDFL in favor of always truncating to the shortest sequence.
!
! - Lazy evaluation. An earlier version of this PEP proposed that
! zip() return a built-in object that performed lazy evaluation
! using __getitem__() protocol. This has been strongly rejected
! by the BDFL in favor of returning a real Python list. If lazy
! evaluation is desired in the future, the BDFL suggests an xzip()
! function be added.
!
! - zip() with no arguments. the BDFL strongly prefers this raise a
! TypeError exception.
!
! - zip() with one argument. the BDFL strongly prefers that this
! return a list of 1-tuples.
!
! - Inner and outer container control. An earlier version of this
! PEP contains a rather lengthy discussion on a feature that some
! people wanted, namely the ability to control what the inner and
! outer container types were (they are tuples and list
! respectively in this version of the PEP). Given the simplified
! API and implementation, this elaboration is rejected. For a
! more detailed analysis, see version 1.7 of this PEP.
***************
*** 409,412 ****
--- 206,210 ----
TBD: URL to python-dev archives
+
Copyright