How does parent of custom exception class get the arguments if I don't call super().__init__()?

Viewed 295

Suppose I create a custom exception class like this:

class MyError(Exception):
    def __init__(self, msg):
        pass

raise MyError('this is an error')

# Traceback (most recent call last):
#   File "<stdin>", line 1, in <module>
# __main__.MyError: this is an error

The MyError class doesn't call super().__init__(), so I don't see any way for the parent class to learn the error message ('this is an error'). Nevertheless, this code works correctly: the error message is indeed stored somewhere in the object and printed when I raise the exception.

How and why is this done? I would expect the parent class to know nothing about the error message if I override __init__() in the child class and don't call super().__init__(). I tried to find Python code for the Exception class, but it looks like it's in C and I was reluctant to dive in and figure it out.

1 Answers

It's kind of weird. BaseException implements both __new__ and __init__, and sets self.args in both methods. Most classes only implement one or the other. You only overrode __init__, so __new__ still receives the arguments.

If you overrode __new__ and prevented the arguments from reaching BaseException.__new__, you'd find the message is lost:

class MyError(Exception):
    def __init__(self, msg):
        pass
    def __new__(cls, msg):
        return super().__new__(cls)
Related