I have doubt in python exception. Below code is taken from python document and I am confuse at one point. If any one can help, will be thankful. Here this codes gives output as:
B C D
class B(Exception):
pass
class C(B):
pass
class D(C):
pass
for cls in [B, C, D]:
try:
raise cls()
except D:
print("D")
except C:
print("C")
except B:
print("B")
If I change except part of code like below code: output will be :
B B B
class B(Exception):
pass
class C(B):
pass
class D(C):
pass
for cls in [B, C, D]:
try:
raise cls()
except B:
print("B")
except C:
print("C")
except D:
print("D")
When I run this code without try block as shown below:
class B(Exception):
pass
class C(B):
pass
class D(C):
pass
for cls in [B, C, D]:
raise cls()
Here output is:
Traceback (most recent call last):
File "C:/Users/885710/Documents/PY/ErrorHandling.py", line 12, in <module>
raise cls()
B
Similary for below code:
class B(Exception):
pass
class C(B):
pass
class D(C):
pass
for cls in [C,B, D]:
raise cls()
Output is this
Traceback (most recent call last):
File "C:/Users/885710/Documents/PY/ErrorHandling.py", line 12, in <module>
raise cls()
C
I confused because, if I run this code separately then it gives output as B or C or D then why in my second code snippet it is giving output as
B
B
B
even though except is define for all 3 Class B, C, D
Python's documentation says:
A class in an except clause is compatible with an exception if it is the same class or a base class
Therefore the given code:
for cls in [B, C, D]:
try:
raise cls()
except D:
print("D")
except C:
print("C")
except B:
print("B")
Can be simplified into the following:
for cls in [B, C, D]:
foo = cls()
if isinstance(foo, D):
print("D")
elif isinstance(foo, C):
print("C")
elif isinstance(foo, B):
print("B")
Then your modification would be turned into:
for cls in [B, C, D]:
foo = cls()
if isinstance(foo, B):
print("B")
elif isinstance(foo, C):
print("C")
elif isinstance(foo, D):
print("D")
So regardless whether foo
is instance of B
, C
or D
it will fulfil the first case, because isinstance
yields True
for instances of a subclass too.
Since B
is the super class of C
and D
your second version will always use the first except
block for B
. Because the Python runtime will search for a matching except
block from top to bottom. An except
block is matching if the exception is an instance of the class in the except
block. If you throw an instance C
for instance this block will match because C()
is (also) an instance of B
.
As a rule of thumb the except
statements must decrease from the most specific condition to the most general condition, e. g.:
try:
throw ...
except D: # the most specific class
print("D")
except C: # is more specific than B but less than D
print("C")
except B: # the most general class in your hierarchy
print("B")
except BaseException as e: the most general exception class
print(e.__class__.__name__)
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