Why does __init__ of Exception require positional (not keyword) arguments in order to stringify exception correctly?

Question:

Can someone clarify the role of super().__init__(a, b, c) in making the second assertion pass? It will fail without it (empty string is returned from str).

Per my understanding Exception is a built-in type that takes no keyword arguments.
But what exactly is happening in Exception when the super().__init__(a, b, c) is called?
Can calling init like that have some unwanted side-effects?

class MyException(Exception):
    def __init__(self, a, b, c):
        self.a = a
        self.b = b
        self.c = c
        super().__init__(a, b, c)

e1 = MyException('a', 'b', 'c')
assert str(e1) == "('a', 'b', 'c')"

e2 = MyException(a='a', b='b', c='c') 
assert str(e2) == "('a', 'b', 'c')" # if "super()..." part above is commented out, this assertion will not pass, because str(e2) is an empty string
Asked By: barciewicz

||

Answers:

The implementation of BaseException.__str__, which you inherit if you don’t otherwise define a __str__ method, only considers the "args" tuple (src). If you pass through as keyword arguments then the "args" will be empty.

Note: it is not necessary to call super().__init__ for custom exception types, unless you need your type to work in cooperative multiple inheritance.

That’s because the exception args attribute, which BaseException.__str__ uses to render the error as a string, is set by the __new__ method.

Answered By: wim
Categories: questions Tags:
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.