How come StopIteration.__base__ is not BaseException?

M

Marco Buttu

Since StopIteration is not an error, how come does it inherit directly
from Exception and not from BaseException?

Thanks in advance, Marco
 
R

random832

Since StopIteration is not an error, how come does it inherit directly
from Exception and not from BaseException?

The reason KeyboardInterrupt and SystemExit inherit from BaseException
is because you often want them to escape (allowing the program to quit)
from code that would otherwise catch them (by catching Exception). On
the contrary, StopIteration is almost always used in a context that
catches it specifically.
 
M

Marco Buttu

The reason KeyboardInterrupt and SystemExit inherit from BaseException
is because you often want them to escape (allowing the program to quit)
from code that would otherwise catch them (by catching Exception). On
the contrary, StopIteration is almost always used in a context that
catches it specifically.

But if I want to catch it specifically (except BaseIteration), why
doesn't it hinerit directly from BaseException? It's not an error and
it's not a warning. I would like to see a piece of code in which it is
useful to catch it generically with a except Exception clause instead of
an except StopIteration...
Regards
 
S

Steven D'Aprano

But if I want to catch it specifically (except BaseIteration), why

You mean StopIteration.
doesn't it hinerit directly from BaseException? It's not an error and
it's not a warning. I would like to see a piece of code in which it is
useful to catch it generically with a except Exception clause instead of
an except StopIteration...

You are focused on the wrong thing. It doesn't matter that we normally
catch StopIteration specifically. We normally catch *all* exceptions
specifically.

try:
...
except ValueError:
...

This doesn't mean that ValueError should inherit from BaseException. So
the fact that we catch StopIteration specifically too doesn't mean it
needs to inherit from BaseException.

What matters is that when you catch "nearly everything", StopIteration is
included in the "nearly everything", but SysExit and KeyboardInterrupt
should not be. Consider:


try:
main()
except Exception as e:
print('an unexpected error occurred')
log_unhandled_exception(e)
emergency_shutdown()
sys.exit(1)
except (KeyboardInterrupt, SysExit):
# User wants to exit.
clean_exit()
sys.exit(0)



Which except clause would you expect an unhandled StopIteration to fall
under? The unexpected error clause, or the "user wants to exit cleanly"
clause?
 
M

Marco Buttu

What matters is that when you catch "nearly everything", StopIteration is
included in the "nearly everything", but SysExit and KeyboardInterrupt
should not be. Consider:


try:
main()
except Exception as e:
print('an unexpected error occurred')
log_unhandled_exception(e)
emergency_shutdown()
sys.exit(1)
except (KeyboardInterrupt, SysExit):
# User wants to exit.
clean_exit()
sys.exit(0)



Which except clause would you expect an unhandled StopIteration to fall
under? The unexpected error clause, or the "user wants to exit cleanly"
clause?

Thanks Steven, that was clear for me. I was thinking about a design
concept: how come doesn't it inherit directly from BaseException like
GeneratorExit does? But I think I got the answer: because we can iterate
manually and so it can propagate, and so we want an except Exception
clause catches it.

Thanks, Marco
 
T

Terry Reedy

Thanks Steven, that was clear for me. I was thinking about a design
concept: how come doesn't it inherit directly from BaseException like
GeneratorExit does? But I think I got the answer: because we can iterate
manually and so it can propagate, and so we want an except Exception
clause catches it.

Until relatively recently, in 2.5, Exception *was* the base exception
class and for nearly everything, it still is. "All built-in,
non-system-exiting exceptions are derived from this class. All
user-defined exceptions should also be derived from this class."
BaseException was added just so it would be possible to catch nearly
everything but a few exceptions. The first two were KeyboardInterrupt
and SystemExit (in 2.5). GeneratorExit was switched in 2.6, but I forget
the details of why.
 
M

Marco Buttu

BaseException was added just so it would be possible to catch nearly
everything but a few exceptions. The first two were KeyboardInterrupt
and SystemExit (in 2.5). GeneratorExit was switched in 2.6, but I forget
the details of why.

Maybe in order to don't catch it inside a generator using a except
Exception clause, because it is used to notify an active generator is
closed:
.... for i in range(10):
.... try:
.... yield i
.... except:
.... print('Catched!')
.... # raise
....Catched!
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
RuntimeError: generator ignored GeneratorExit

Do you remember if this is the reason? Thanks,
 
E

Ethan Furman

Since StopIteration is not an error, how come does it inherit directly from Exception and not from BaseException?

Not all exceptions are errors. (Although not dealing with one can be. ;)
 
T

Terry Reedy

Maybe in order to don't catch it inside a generator using a except
Exception clause, because it is used to notify an active generator is
closed:

... for i in range(10):
... try:
... yield i
... except:
... print('Catched!')
... # raise
...
Catched!
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
RuntimeError: generator ignored GeneratorExit

Do you remember if this is the reason? Thanks,

I only remember that there was a 'problem' that necessitated a change in
2.6 after the introduction in 2.5. The above seems reasonable.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,774
Messages
2,569,599
Members
45,175
Latest member
Vinay Kumar_ Nevatia
Top