Terry Reedy wrote:
On 9/11/2011 12:01 AM, Ian Kelly wrote:
On Sat, Sep 10, 2011 at 1:36 PM, Terry Reedy<tjre...@udel.edu> wrote:
The statement containing the explicit next(items) call can optionally be
wrapped to explicitly handle the case of an empty iterable in whatever
manner is desired.
try:
<set up with next(items)>
except StopIteration:
raise ValueError("iterable cannot be empty")
The only time that's optional
This is an opinion, or rather, a programming philosophy based on
technical facts, rather than a fact itself. You do raise an important
issue.
is when you're writing an iterator and
the try-except would end up looking like this:
try:
# do stuff with next(items)
except StopIteration:
raise StopIteration
And even then, it's probably a good idea to clearly document that
you're allowing a StopIteration from one iterator to propagate up as a
StopIteration for another.
In the yield-pairs example,
def pairs(iterable):
it = iter(iterable)
for i in it:
yield i, next(it)
ignoring StopIteration from the get-even explicit next means ignoring an
odd item. If pairs() were in a general purpose library, it should have a
doc string that specifies that, and a test case with an odd number of
items. I would consider a comment in the code itself to be optional,
depending on the intended or expected human audience and the context of
presentation. In this context, the explanation is in the text that
surrounds the code.
Apart from that case, whenever you call next() you should always be
prepared to catch a StopIteration.
To me, it depends on the contract or specification of the function. If
the behavior for an empty input iterator is not specified, then there is
no basis for writing the body of an except clause.
While in the past few months I have written examples of all of the three
explicit-next use cases I gave, I was prompted to write them up now by
Tigerstyle's 'Doctest failing' thread. The specification by example
(perhaps given by an instructor) did not include an empty title that
would lead to an empty list of title words. Certainly, the doc for
def fix_title(title):
small_words = ('into', 'the', 'a', 'of', 'at', 'in', 'for', 'on')
twords = iter(title.strip().lower().split())
new_title = [next(twords)]
for word in twords:
if word not in small_words:
word = word.title()
new_title.append(word)
return(' '.join(new_title))
should start "Given a title with at least one word, ...".
The Agile Programming Test-Driven-Development maxim, 'Write the minimum
code needed to pass the test' says that the extra lines needed to catch
and process StopIteration should *not* be written until there is a test
case leading to such.
Letting a StopIteration propagate
up the stack to parts unknown is bad juju because it's a flow control
exception, not an error-signaling exception. If it happens to
propagate up to another for loop, then it will break out of the for
loop, and the exception will simply be swallowed.
What you are saying is a) that the following code
for title in ['amazinG', 'a helL of a fiGHT', '', 'igNordEd']:
print(fix_title(title))
will print 'Amazing', 'A Hell of a Fight', and stop; b) that this is the
worst choice of how to handle the empty title; and c) that in real world
world programming, *someone* should decide whether fix_title('') returns
'' or raises ValueError.
A counter-argument could be 1. that when a function's contract is
violated, invoking unspecified behavior, anything is allowed; or 2. that
titles are checked for actual content before the case fixup is called,
and the time and mental energy required to define and test behavior for
impossible input is wasted and better spent on something more useful.
Having spent hours tracking down errors because somebody did not address
a corner case, I find counter-argument 1 unhelpful.
Counter-argument 2 I can at least partially agree with; however, in this
case where the uncaught exception can mess up flow control elsewhere I
do not -- the StopIteration should be caught and changed to something
appropriate, such as EmptyTitle (assuming blank titles are errors --
which they probably should be... "Hello, do you have the book '' for
sale here?")
~Ethan~
--
http://mail.python.org/mailman/listinfo/python-list