Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

Here's the syntax for iterators in Java (somewhat similar syntax in C#):

Iterator it = sequence.iterator();

while (it.hasNext()) {
    System.out.println(it.next());
}

Which makes sense. Here's the equivalent syntax in Python:

it = iter(sequence)
while True:
    try:
        value = it.next() 
    except StopIteration:
        break
    print(value)

I thought Exceptions were supposed to be used only in, well, exceptional circumstances.

Why does Python use exceptions to stop iteration?

share|improve this question

4 Answers 4

up vote 25 down vote accepted

There's a very Pythonic way to write that expression without explicitly writing a try-except block for a StopIteration:

it = iter(sequence)
for value in it:
    print value

You can read up on the relevant PEPs 234 255 if you want to know more behind why StopIteration was introduced and the logic behind iterators.

A general principle in Python is to have one way to do something (see import this), and preferably it's beautiful, explicit, readable, and simple, which the Pythonic method satisfies. Your equivalent code is only necessary as Python doesn't give iterators a hasNext member function, preferring people to just loop through the iterators directly (and if you need to do something else to just try reading it and catch an exception).

This automatic catching of a StopIteration exception at the end of an iterator makes sense and is an analogue of the EOFError raised if you read past an end of file.

share|improve this answer
4  
The "Pythonic" way sure seems a lot more like "for value in sequence:" rather than "for value in iter(sequence):".. Update post? –  Yam Marcovic Oct 5 '11 at 16:12
10  
@Yam: I agree. Its not pythonic to take an existing sequence and convert it into an iterator just to apply a for loop to it; the sequence is already an iterable, so the conversion of a list to a listiterator is pointless. I kept the first line only to follow NullUserException's starting point, to explain how you should loop over an iterator, which is the same way you should loop over any iterable (list, set, str, tuple, dict, file, generator, etc.). I could have done something like it = itertools.combinations("ABCDE", 2) to get a better example of a meaningful iterator. –  dr jimbob Oct 5 '11 at 18:18
    
Mhm, I see. Thanks for the detailed reply. –  Yam Marcovic Oct 5 '11 at 19:40

The reason why python uses an Exception to stop an iteration is documented in PEP 234:

It has been questioned whether an exception to signal the end of the iteration isn't too expensive. Several alternatives for the StopIteration exception have been proposed: a special value End to signal the end, a function end() to test whether the iterator is finished, even reusing the IndexError exception.

  • A special value has the problem that if a sequence ever contains that special value, a loop over that sequence will end prematurely without any warning. If the experience with null-terminated C strings hasn't taught us the problems this can cause, imagine the trouble a Python introspection tool would have iterating over a list of all built-in names, assuming that the special End value was a built-in name!

  • Calling an end() function would require two calls per iteration. Two calls is much more expensive than one call plus a test for an exception. Especially the time-critical for loop can test very cheaply for an exception.

  • Reusing IndexError can cause confusion because it can be a genuine error, which would be masked by ending the loop prematurely.

Note: the idiomatic python way to loop over a sequence is like this:

it = iter(sequence)
for value in it:
    print (value)
share|improve this answer

It's a difference in philosophy. The Pythonic design philosophy is EAFP:

Easier to ask for forgiveness than permission. This common Python coding style assumes the existence of valid keys or attributes and catches exceptions if the assumption proves false. This clean and fast style is characterized by the presence of many try and except statements. The technique contrasts with the LBYL style common to many other languages such as C...

share|improve this answer

It's just that the Java implementation has a hasNext() so that you can check before hit a next() on an empty iterator. When you do call next() on a Java iterator with no elements left, a NoSuchElementException is thrown.

So effectively, you can do a try..catch in Java like the try..except in Python. And yes, as per a previous answer, philosophy is very important in the Pythonic world.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.