Python: User-Defined Exception That Proves The Rule
Python documentations states:
Exceptions should typically be derived from the Exception class, either directly or indirectly.
the word 'typically'
leaves me in an ambiguous state.
consider the code:
class good(Exception): pass
class bad(object): pass
Heaven = good()
Hell = bad()
>>> raise Heaven
Traceback (most recent call last):
File "<pyshell#163>", line 1, in <module>
raise Heaven
good
>>> raise Hell
Traceback (most recent call last):
File "<pyshell#171>", line 1, in <module>
raise Hell
TypeError: exceptions must be classes or instances, not bad
so when reading the python docs, should i replace 'typically'
with ''
?
what if i have a class hierarchy that has nothing to do with the Exception class, and I want to 'raise' objects belonging to the hierarchy?
I can always raise an exception with an argument:
raise Exception, Hell
This seems slightly awkward to me
What's so special about the Exception (EDIT: or BaseException) class, that only i开发者_JAVA技巧ts family members can be raised?
There are other valid classes you can inherit from apart from Exception
, for example BaseException
.
See the documentation for the exception hierarchy.
BaseException
+-- SystemExit
+-- KeyboardInterrupt
+-- GeneratorExit
+-- Exception
+-- StopIteration
+-- StandardError
etc..
In older versions of Python it was possible to throw things other than exceptions. For example in Python 2.5:
>>> raise "foo"
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
foo
But you get this deprecation warning:
DeprecationWarning: raising a string exception is deprecated
In newer versions this is not allowed. Everything you raise must derive from BaseException.
"so when reading the python docs, should i change 'typically' with ''?"
No.
Typically, you inherit from Exception. Period. That's what it says.
Sometimes, you might inherit from BaseException. That's what it doesn't say. You might extend BaseExcetion because you want to defeat except Exception
handlers.
What's so special about ...
They're subclasses of BaseException
. What more do you need to know? The source is readily available. You can read the source code for the raise
statement to see exactly what it checks before it throws the TypeError
.
http://svn.python.org/view/python/trunk/Python/ceval.c?annotate=80817
Lines 3456 to 3563.
However, all that matters from a practical stand-point is "subclasses of BaseException
."
'Typically' is used because there are a few very rare types of exception that don't want to be caught by a generic Exception
handler. If in doubt inherit from Exception
, but there are exceptions to that rule.
Most exceptions are used to indicate some sort of error or exceptional condition that is a result of the code and data. These exceptions are all subclasses of Exception
. If you want to raise your own exception it will probably fall into that category and should therefore also inherit Exception
. If you want a generic exception handler, e.g. to log errors then it is perfectly reasonable to catch Exception
and expect to catch any errors that way.
The other exceptions which inherit directly from BaseException
are slightly different. SystemExit
is raised when you call sys.exit()
(or you can raise it directly). If you do have some top level code that logs errors then you probably don't want it to handle SystemExit
in the same way. You used to have to include a separate handler for SystemExit
just to stop the generic Exception handler catching that case.
KeyboardInterrupt
does represent an unexpected condition, but it's one that is raised by external input from the user so it can happen anywhere in your code; it doesn't depend in any way on the code or data. That means even if you do want to handle it you probably want to handle it differently than the exceptions which inherit from Exception
.
Things derived from the various error/exception classes can also be raised, but those are generally reserved for other things.
Sometimes you might want to raise things you do not consider an exception (but the rule). For these rare cases one can consider it nice to raise
something else besides just exceptions.
In a recursive computation in which at some point an answer is found, raising it to the upwardly waiting catcher can be pretty neat (instead of return
ing it which means the recursion has to expect this, pass it upwards as well etc.).
But nowadays only old-style classes (for compatibility reasons I guess) and derivations from BaseException can be raised because too many people abused things like strings for exceptions.
精彩评论