4

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

5
  • C is B, and D is C (which in turn is B), so (transitively) D is B (this is what inheritance is all about). The order that you are trying to handle exceptions is important (in this case). Probably you should extend all of your classes from Exception (instead of one from another - like you do now), and you'd get the behavior you desire in your 2nd snippet (without changing the other scenario(s)). class C(Exception):, class D(Exception):. Commented Oct 19, 2018 at 10:52
  • Probably you should extend all of your classes from Exception>> can u please explain with example? Commented Oct 19, 2018 at 10:55
  • If D is C and C is B hence D is B, then why it print B,C,D in first snippet and B,B,B in second. Still didnt get the point Commented Oct 19, 2018 at 10:58
  • Because is is one way only: C is B, but B is not C. Commented Oct 19, 2018 at 11:00
  • Ok Thank u.. got it. Commented Oct 19, 2018 at 11:01

3 Answers 3

2

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.

Sign up to request clarification or add additional context in comments.

1 Comment

Thanx for adding up one more explanation. Great help!
1

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__)

1 Comment

Excellent! Thank u so much for the explanation.
1

Let's first understand the class hierarchy involved in this code sample

class B(Exception):
    pass
class C(B):
    pass
class D(C):
    pass

B -> Base class

C -> inherits from B

D -> inherits from C and C -> inherits from B

thus D -> inherits from B and C

A try statement may have more than one except clause for different exceptions. But at most one except clause will be executed

Unless you are catching the raised the exception then base class is given the priority to be caught. i.e when exception classes are inherited then the priority in the except is given to the BASE class (in your code it's class B).

Now the first case :

for cls in [B, C, D]:
    try:
        raise cls()
    except D:
        print("D")
    except C:
        print("C")
    except B:
        print("B")

Iteration 1 : element : B

First control checks the except D as it's not a base class nor the matching class to the raised one then control will move to except C and at last it will execute except B, thus prints B.

Iteration 2 : element : C

First control checks the except D as it's not a base class nor the matching class to the raised one then control will move to except C and will execute except C, thus prints C

Iteration 3 : element : D

First control checks the except D as it's a matching class then control will execute except D, thus prints D

Now consider Second case :

for cls in [B, C, D]:
    try:
        raise cls()
    except B:
        print("B")
    except C:
        print("C")
    except D:
        print("D")

Here B is the base class for classes C and D so when you write except B at the top of except stack then the control does not go to subsequent except C and except D. So it prints output as B for each iteration of for loop.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.