I was taking a look at the hierarchy of the built-in python exceptions, and I noticed that StopIteration
and GeneratorExit
have different base classes:
BaseException
+-- SystemExit
+-- KeyboardInterrupt
+-- GeneratorExit
+-- Exception
+-- StopIteration
+-- StandardError
+-- Warning
Or in code:
>>> GeneratorExit.__bases__
(<type 'exceptions.BaseException'>,)
>>> StopIteration.__bases__
(<type 'exceptions.Exception'>,)
When I go to the specific description of each exception, I can read following:
https://docs.python.org/2/library/exceptions.html#exceptions.GeneratorExit
exception GeneratorExit
Raised when a generator‘s close() method is called. It directly inherits from BaseException instead of StandardError since it is technically not an error.
https://docs.python.org/2/library/exceptions.html#exceptions.StopIteration
exception StopIteration
Raised by an iterator‘s next() method to signal that there are no further values. This is derived from Exception rather than StandardError, since this is not considered an error in its normal application.
Which is not very clear to me. Both are similar in the sense that they do not notify errors, but an "event" to change the flow of the code. So, they are not technically errors, and I understand that they should be separated from the rest of the exceptions... but why is one a subclass of BaseException
and the other one a subclass of Exception
?.
In general I considered always that Exception
subclasses are errors, and when I write a blind try: except:
(for instance calling third party code), I always tried to catch Exception
, but maybe that is wrong and I should be catching StandardError
.
There are different kind of exceptions like ZeroDivisionError, AssertionError etc. All exception classes are derived from the BaseException class.
The BaseException class is, as the name suggests, the base class for all built-in exceptions in Python. Typically, this exception is never raised on its own, and should instead be inherited by other, lesser exception classes that can be raised.
In Python, all exceptions must be instances of a class that derives from BaseException . In a try statement with an except clause that mentions a particular class, that clause also handles any exception classes derived from that class (but not exception classes from which it is derived).
exception Exception The root class for exceptions. All built-in exceptions are derived from this class. All user-defined exceptions should also be derived from this class, but this is not (yet) enforced.
It is quite common to use try: ... except Exception: ... blocks.
If GeneratorExit would inherit from Exception you would get the following issue:
def get_next_element(alist):
for element in alist:
try:
yield element
except BaseException: # except Exception
pass
for element in get_next_element([0,1,2,3,4,5,6,7,8,9]):
if element == 3:
break
else:
print(element)
0
1
2
Exception ignored in: <generator object get_next_element at 0x7fffed7e8360>
RuntimeError: generator ignored GeneratorExit
This example is quite simple but imagine in the try block a more complex operation which, in case of failure, would simply ignore the issue (or print a message) and get to the next iteration.
If you would catch the generic Exception, you would end up preventing the user of your generator from breaking the loop without getting a RuntimeError.
A better explanation is here.
EDIT: answering here as it was too long for a comment.
I'd rather say the opposite. GeneratorExit
should inherit from Exception
rather than BaseException
. When you catch Exception
you basically want to catch almost everything. BaseException
as PEP-352 states, is for those exceptions which need to be "excepted" in order to allow the user to escape from code that would otherwise catch them. In this way you can, for example, still CTRL-C running code. GeneratorExit
falls into that category in order to break loops. An interesting conversation about it on comp.lang.python.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With