Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.python > #13198 > unrolled thread

Re: Idioms combining 'next(items)' and 'for item in items:'

Started byTerry Reedy <tjreedy@udel.edu>
First post2011-09-12 16:51 -0400
Last post2011-09-12 16:51 -0400
Articles 1 — 1 participant

Back to article view | Back to comp.lang.python

This discussion starts older than the indexed window; earlier articles aren't shown. The article labeled Started by below is the oldest one visible, not the original post.


Contents

  Re: Idioms combining 'next(items)' and 'for item in items:' Terry Reedy <tjreedy@udel.edu> - 2011-09-12 16:51 -0400

#13198 — Re: Idioms combining 'next(items)' and 'for item in items:'

FromTerry Reedy <tjreedy@udel.edu>
Date2011-09-12 16:51 -0400
SubjectRe: Idioms combining 'next(items)' and 'for item in items:'
Message-ID<mailman.1047.1315860683.27778.python-list@python.org>
On 9/12/2011 12:55 PM, Ian Kelly wrote:
> On Sun, Sep 11, 2011 at 6:45 PM, Terry Reedy<tjreedy@udel.edu>  wrote:
>> whereas, you are right, it breaks it noisily in the body. So Ian's claim
>> that StopIteration must be caught to avoid silent termination is not true.
>> Thanks for pointing out what I saw but did not cognize the full implication
>> of before. A better exception and an error message with an explaination
>> might still be a good idea, though.
>
> But you can't write the function under the assumption that it will
> only be called from the function body.

Sigh. You are right.

>  The following is a slight
> reorganization of your example that does exhibit the problem:
>
> for title in map(fix_title, ['amazinG', 'a helL of a fiGHT', '', 'igNordEd']):
>      print(title)
>
> Output:
> amazing
> a Hell of a Fight
>
> Note that at first glance, my example would appear to be functionally
> equivalent to yours -- I've merely pulled the fix_title call out of
> the loop body and into the iterator.  But actually they produce
> different results because fix_title misbehaves by not catching the
> StopIteration.

You are right, non-iterators should not raise or pass on StopIteration. 
There are actually several reasons.

1. The manual defined StopIteration as meaning '[I have] no more values 
[to give you]'. This is only meaningful coming from an iterator.

2. Your particular point is that StopIteration is (almost) unique in 
being sometimes, but only sometimes, caught by the interpreter, rather 
than just by user except clauses. AttributeError is another, which has 
occasionally caused its own problems. But we cannot stop raising 
AttributeError while we can always catch StopIteration for explicit 
next() (and should outside of iterators).

3. In the case of grabbing the first item from an iterator, no first 
item is a boundary case for the expected, legal type of input. I believe 
boundary cases should be included in function specifications. While 
there may be a couple of choices as to response, that is much less than 
infinity. For fix_title, the choices are ValueError or ''. Any other 
return would be an error unless explicitly given in the specs. So the 
boundary case should be included in the test suite to exclude any other 
random response.

4. StopIteration is an artifact of the choice of implementation. Pulling 
the first item out before the loop is an alternative to a flag and 
testing within the loop. Such an implementation detail should not leak 
into the user's view of the function as an abstraction.

If fix_title were a generator function whose instances yielded fixed 
title words one at a time, then the bare next() would be correct (as you 
noted). But it is not, and the difference is important, more important 
than having 'minimal clean code'. Thank you for persisting until I saw 
that in this context.

-- 
Terry Jan Reedy

[toc] | [standalone]


Back to top | Article view | comp.lang.python


csiph-web