How does an exception compare in an except clause
In the following code segment:
try:
raise Bob()
except Fred:
print "blah"
How is Bob and Fred compared?
From playing around it seems to be causing the isinstance at the bottom, is that correct?
I ask because I am trying to undermine the process, in particular I want to be able to build Bob in such a way that he is caught by execpt Fred even if he is not actually an instance of Fred or any of its subclasses.
Several people have asked why I am trying to do this ...
We have an RMI system that is based on a philosophy to make it as seamless as possible, here is a short example of use here, note that there is no socket code in the RMI system, an example.
import remobj
socket = remobj.RemObj("remote_server_name").getImport("socket")
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.bind(("", 0))
print "listening on port:", s.getsockname()[1]
s.settimeout(10)
try:
print "received:", s.recv(2048)
except socket.timeout:
print "timeout"
Now, in this particular example, the exception doesn't work as expected because the object raised is not an instance of socket.timeout, it is an instance of one of our proxy helper classes.
a source to share
I believe your guess is correct on how the comparison works, and the only way to catch this is to add Fred as a base class for Bob. For instance:
# Assume both Bob and Fred are derived from Exception
>>> class Bob(Bob, Fred):
... pass
...
>>> try:
... raise Bob()
... except Fred:
... print 'blah'
blah
As far as I know, this is the only way to make it work the way you wrote it. However, if you just rewrote the except line:
... except (Bob, Fred):
He would have caught both Bob and Fred without requiring a modification to Bob's definition.
a source to share
I want to be able to construct Bob in such a way that it hits Fred's execpt, even though it's not actually an instance of Fred or any of its subclasses.
Well, you can just catch the "Exception" - but that's not very pythonic. You should try to catch the correct exception and then revert to the generic exception (which all exceptions were subclassed) as a last resort. If that doesn't work for you, then something went wrong in your design phase.
See this note from Code Like A Pythonista
Note. Always specify exceptions to catch. Never use anything other than suggestions. Bare besides articles will catch unexpected exceptions, the code is extremely difficult to debug.
However, one of the idioms in Zen Python is
Special cases are not hard enough to break the rules. Although practicality trumps cleanliness.
a source to share
>>> class Fred(Exception):
pass
>>> class Bob(Fred):
pass
>>> issubclass(Bob, Fred)
True
>>> issubclass(Fred, Bob)
False
>>> try:
raise Bob()
except Fred:
print("blah")
blah
So basically the exception is caught because Bob is a subclass of Fred I suppose they either had to implement logic similar to issubclass(Bob, Fred)
See, this is how you want to implement whatever you want. Of course, not in init , but in another method.
>>> class Bob(Exception):
def __init__(self):
raise Fred
>>> try:
b = Bob()
except Fred:
print('blah')
blah
a source to share
I don't understand how to hide your exception in socket.timeout adhears to a "seamless" philosophy? What's wrong with catching the expected exception as defined?
try:
print "received:", s.recv(2048)
except socket.timeout:
print "timeout"
except our_proxy_helper_class:
print 'crap!'
Or, if you really want to catch it as socket.timeout, why not just increase socket.timeout in our_proxy_helper_class?
raise socket.timeout('Method x timeout')
So when you raise socket.timeout in our_proxy_helper_class it should be caught by "except socket.timeout".
a source to share
In CPython, at least it looks like there is a COMPARE_OP operation with type 10 (Exception Matching). There is hardly anything you can do to break this calculation.
>>> import dis
>>> def foo ():
... try:
... raise OSError ()
... except Exception, e:
... pass
...
>>> dis.dis (foo)
2 0 SETUP_EXCEPT 13 (to 16)
3 3 LOAD_GLOBAL 0 (OSError)
6 CALL_FUNCTION 0
9 RAISE_VARARGS 1
12 POP_BLOCK
13 JUMP_FORWARD 21 (to 37)
4 >> 16 DUP_TOP
17 LOAD_GLOBAL 1 (Exception)
20 COMPARE_OP 10 (exception match)
23 JUMP_IF_FALSE 9 (to 35)
26 POP_TOP
27 POP_TOP
28 STORE_FAST 0 (e)
31 POP_TOP
5 32 JUMP_FORWARD 2 (to 37)
>> 35 POP_TOP
36 END_FINALLY
>> 37 LOAD_CONST 0 (None)
40 RETURN_VALUE a source to share