Mailing List Archive

CVS: python/nondist/peps pep-0279.txt,1.8,1.9
Update of /cvsroot/python/python/nondist/peps
In directory usw-pr-cvs1:/tmp/cvs-serv22571

Modified Files:
pep-0279.txt
Log Message:
Raymond's latest update. Note Status is still Draft until
confirmation of Accepted status comes from Guido.


Index: pep-0279.txt
===================================================================
RCS file: /cvsroot/python/python/nondist/peps/pep-0279.txt,v
retrieving revision 1.8
retrieving revision 1.9
diff -C2 -d -r1.8 -r1.9
*** pep-0279.txt 21 Mar 2002 05:54:14 -0000 1.8
--- pep-0279.txt 1 Apr 2002 16:04:27 -0000 1.9
***************
*** 13,17 ****
Abstract

! This PEP introduces three orthogonal (not mutually exclusive) ideas
for enhancing the generators introduced in Python version 2.2 [1].
The goal is to increase the convenience, utility, and power
--- 13,17 ----
Abstract

! This PEP introduces two orthogonal (not mutually exclusive) ideas
for enhancing the generators introduced in Python version 2.2 [1].
The goal is to increase the convenience, utility, and power
***************
*** 50,54 ****
The next steps in the evolution of generators are:

! 1. Add a new builtin function, indexed() which was made possible
once iterators and generators became available. It provides
all iterables with the same advantage that iteritems() affords
--- 50,54 ----
The next steps in the evolution of generators are:

! 1. Add a new builtin function, iterindexed() which was made possible
once iterators and generators became available. It provides
all iterables with the same advantage that iteritems() affords
***************
*** 59,75 ****
a generator whenever memory issues arise.

- 3. Add a generator method to enable exceptions to be passed to a
- generator. Currently, there is no clean method for triggering
- exceptions from outside the generator. Also, generator exception
- passing helps mitigate the try/finally prohibition for generators.
-
All of the suggestions are designed to take advantage of the
existing implementation and require little additional effort to
incorporate. Each is backward compatible and requires no new
! keywords. The three generator tools go into Python 2.3 when
generators become final and are not imported from __future__.



Reference Implementation

--- 59,81 ----
a generator whenever memory issues arise.

All of the suggestions are designed to take advantage of the
existing implementation and require little additional effort to
incorporate. Each is backward compatible and requires no new
! keywords. The two generator tools go into Python 2.3 when
generators become final and are not imported from __future__.



+ BDFL Pronouncements
+
+ 1. The new built-in function is ACCEPTED. There needs to be further
+ discussion on the best name for the function.
+
+ 2. Generator comprehensions are REJECTED. The rationale is that
+ the benefits are marginal since generators can already be coded directly
+ and the costs are high because implementation and maintenance require
+ major efforts with the parser.
+
+
Reference Implementation

***************
*** 92,104 ****


! Specification for a new builtin:

! def indexed(collection, start=0, stop=None):
! 'Generates an indexed series: (0,seqn[0]), (1,seqn[1]) ...'
! gen = iter(collection)
! cnt = start
! while stop is None or cnt<stop:
! yield (cnt, gen.next())
! cnt += 1


--- 98,111 ----


! Specification for a new builtin [ACCEPTED PROPOSAL]:

!
! def iterindexed(collection):
! 'Generates an indexed series: (0,seqn[0]), (1,seqn[1]) ...'
! i = 0
! it = iter(collection)
! while 1:
! yield (i, it.next())
! i += 1


***************
*** 116,120 ****
There are other PEPs which touch on related issues: integer iterators,
integer for-loops, and one for modifying the arguments to range and
! xrange. The indexed() proposal does not preclude the other proposals
and it still meets an important need even if those are adopted -- the need
to count items in any iterable. The other proposals give a means of
--- 123,127 ----
There are other PEPs which touch on related issues: integer iterators,
integer for-loops, and one for modifying the arguments to range and
! xrange. The iterindexed() proposal does not preclude the other proposals
and it still meets an important need even if those are adopted -- the need
to count items in any iterable. The other proposals give a means of
***************
*** 130,141 ****
part of a core programming style, applicable to any object with an
iterable interface. Just as zip() solves the problem of looping
! over multiple sequences, the indexed() function solves the loop
counter problem.

! If only one builtin is allowed, then indexed() is the most important
general purpose tool, solving the broadest class of problems while
improving program brevity, clarity and reliability.


Comments from GvR: filter and map should die and be subsumed into list
comprehensions, not grow more variants. I'd rather introduce builtins
--- 137,169 ----
part of a core programming style, applicable to any object with an
iterable interface. Just as zip() solves the problem of looping
! over multiple sequences, the iterindexed() function solves the loop
counter problem.

! If only one builtin is allowed, then iterindexed() is the most important
general purpose tool, solving the broadest class of problems while
improving program brevity, clarity and reliability.


+ Note C: Various alternative names have been proposed:
+
+ iterindexed()-- five syllables is a mouthfull
+ index() -- nice verb but could be confused the .index() method
+ indexed() -- widely liked however adjectives should be avoided
+ count() -- direct and explicit but often used in other contexts
+ itercount() -- direct, explicit and hated by more than one person
+ enumerate() -- a contender but doesn't mention iteration or indices
+ iteritems() -- conflicts with key:value concept for dictionaries
+
+
+ Note D: This function was originally proposed with optional start and
+ stop arguments. GvR pointed out that the function call
+ iterindexed(seqn,4,6) had an alternate, plausible interpretation as a
+ slice that would return the fourth and fifth elements of the sequence.
+ To avoid the ambiguity, the optional arguments were dropped eventhough
+ it meant losing flexibity as a loop counter. That flexiblity was most
+ important for the common case of counting from one, as in:
+ for linenum, line in iterindexed(source): print linenum, line
+
+
Comments from GvR: filter and map should die and be subsumed into list
comprehensions, not grow more variants. I'd rather introduce builtins
***************
*** 143,146 ****
--- 171,180 ----
an example).

+ I like the idea of having some way to iterate over a sequence and
+ its index set in parallel. It's fine for this to be a builtin.
+
+ I don't like the name "indexed"; adjectives do not make good
+ function names. Maybe iterindexed()?
+
Comments from Ka-Ping Yee: I'm also quite happy with everything you
proposed ... and the extra builtins (really 'indexed' in particular)
***************
*** 159,164 ****
a good idea.

! Comments from the Community: The response to the indexed() proposal has
! been close to 100% favorable. Almost everyone loves the idea.

Author response: Prior to these comments, four builtins were proposed.
--- 193,198 ----
a good idea.

! Comments from the Community: The response to the iterindexed() proposal
! has been close to 100% favorable. Almost everyone loves the idea.

Author response: Prior to these comments, four builtins were proposed.
***************
*** 174,178 ****


! Specification for Generator Comprehensions:

If a list comprehension starts with a 'yield' keyword, then
--- 208,212 ----


! Specification for Generator Comprehensions [REJECTED PROPOSAL]:

If a list comprehension starts with a 'yield' keyword, then
***************
*** 238,241 ****
--- 272,284 ----
just don't think that's where its future lies.

+ I don't think it's worth the trouble. I expect it will take a lot
+ of work to hack it into the code generator: it has to create a
+ separate code object in order to be a generator. List
+ comprehensions are inlined, so I expect that the generator
+ comprehension code generator can't share much with the list
+ comprehension code generator. And this for something that's not
+ that common and easily done by writing a 2-line helper function.
+ IOW the ROI isn't high enough.
+
Comments from Ka-Ping Yee: I am very happy with the things you have
proposed in this PEP. I feel quite positive about generator
***************
*** 276,376 ****
readable as compared to a separate function definition with an
embedded yield.
-
-
-
- Specification for Generator Exception Passing:
-
- Add a .throw(exception) method to the generator interface:
-
- def logger():
- start = time.time()
- log = []
- try:
- while 1:
- log.append( time.time() - start )
- yield log[-1]
- except WriteLog:
- return log
-
- g = logger()
- for i in [10,20,40,80,160]:
- testsuite(i)
- g.next()
- g.throw(WriteLog)
-
- There is no existing work-around for triggering an exception
- inside a generator. This is a true deficiency. It is the only
- case in Python where active code cannot be excepted to or through.
-
- Generator exception passing also helps address an intrinsic limitation
- on generators, the prohibition against their using try/finally to
- trigger clean-up code [1]. Without .throw(), the current work-around
- forces the resolution or clean-up code to be moved outside the generator.
-
-
- Note A: The name of the throw method was selected for several
- reasons. Raise is a keyword and so cannot be used as a method
- name. Unlike raise which immediately raises an exception from the
- current execution point, throw will first return to the generator
- and then raise the exception. The word throw is suggestive of
- putting the exception in another location. The word throw is
- already associated with exceptions in other languages.
-
- Alternative method names were considered: resolve(), signal(),
- genraise(), raiseinto(), and flush(). None of these seem to fit
- as well as throw().
-
-
- Note B: The throw syntax should exactly match raise's syntax:
-
- throw([expression, [expression, [expression]]])
-
- Accordingly, it should be implemented to handle all of the following:
-
- raise string g.throw(string)
- raise string, data g.throw(string,data)
- raise class, instance g.throw(class,instance)
- raise instance g.throw(instance)
- raise g.throw()
-
-
- Comments from GvR: I'm not convinced that the cleanup problem that
- this is trying to solve exists in practice. I've never felt the need
- to put yield inside a try/except. I think the PEP doesn't make enough
- of a case that this is useful.
-
- Comments from Ka-Ping Yee: I agree that the exception issue needs to
- be resolved and [that] you have suggested a fine solution.
-
- Comments from Neil Schemenauer: The exception passing idea is one I
- hadn't thought of before and looks interesting. If we enable the
- passing of values back, then we should add this feature too.
-
- Comments for Magnus Lie Hetland: Even though I cannot speak for the
- ease of implementation, I vote +1 for the exception passing mechanism.
-
- Comments from the Community: The response has been mostly favorable. One
- negative comment from GvR is shown above. The other was from Martin von
- Loewis who was concerned that it could be difficult to implement and
- is withholding his support until a working patch is available. To probe
- Martin's comment, I checked with the implementers of the original
- generator PEP for an opinion on the ease of implementation. They felt that
- implementation would be straight-forward and could be grafted onto the
- existing implementation without disturbing its internals.
-
- Author response: When the sole use of generators is to simplify writing
- iterators for lazy producers, then the odds of needing generator
- exception passing are slim. If, on the other hand, generators
- are used to write lazy consumers, create coroutines, generate output
- streams, or simply for their marvelous capability for restarting a
- previously frozen state, THEN the need to raise exceptions will
- come up frequently.
-
- I'm no judge of what is truly Pythonic, but am still astonished
- that there can exist blocks of code that can't be excepted to or
- through, that the try/finally combination is blocked, and that the
- only work-around is to rewrite as a class and move the exception
- code out of the function or method being excepted.
-


--- 319,322 ----