Loading video player…

Inheritance in Python

00:00 You’re almost always using some form of inheritance within Python, even if you don’t explicitly declare it. To demonstrate that, I’m going to use the Python interactive shell. I’m going to start by creating a new class called MyClass—a very creative name.

00:19 I want to leave this class blank, and so I’ll just write pass here. pass is a special keyword that will allow you to create a function, class, or loop that is effectively empty.

00:33 Now, I will instantiate this class into a new object called c. Python has a built-in function called dir(), which returns a list of all the members of the class you pass in. A class’s members are just the attributes and methods that make up the class, including the special .__init__() method that’s used for object instantiation.

00:59 But we didn’t declare any attributes or methods, so this class has no members, right? Let’s find out.

01:08 That’s probably not what you were expecting. What are all of these members with double underscores (__), and where are they coming from? These members are actually all methods called magic methods, or dunder methods,

01:23 named after their double underscores. Some of these may look familiar to you, such as __init__, which we use as the constructor for constructing new classes.

01:35 We also used __init__ to declare instance attributes. To explain where these are coming from, let me create one more object and list its members.

01:49 And would you look at that? It looks like the o object and the c object have very similar members, except the c object—which came from our custom class—has some extra members, like __weakref__.

02:04 You might be able to guess what’s going on here, but let me explain. This o object was instantiated from the object class, which is super confusing considering we’ve been calling every instance of any class an object. Well, this object class is not a class that we define ourselves.

02:24 It’s built into Python and it’s this object class that defines these strange members that we’re seeing. And, as it turns out, every custom class that we create automatically inherits from this object class behind the scenes, even if we don’t explicitly make it.

02:45 That explains why the c object has all of these members too—it inherited it from the object class. The extra members present in our custom class came from elsewhere, but that’s beyond the scope of this course.

03:00 The point is every class in Python implicitly inherits from this object superclass, which defines all these magic methods that Python uses to manage our objects.

03:14 Another place where inheritance is used is with exceptions. Exception objects are special in that they can be thrown up a call stack and caught anywhere along that stack.

03:27 If no code catches that exception object before it reaches the top, the program crashes and you’re left with a stack trace. If you’re interested in learning more about exceptions, we have a course for that, which I will link down in the video notes below.

03:45 Let’s see how they work with inheritance. Someone new to exceptions might try to create their own exception class as if it were a normal class, just like this.

03:59 Exceptions can be raised with the raise keyword. This is similar to throw in other languages. All right, we got a stack trace—but it’s not from our exception.

04:12 There’s a TypeError—not MyError. Python has identified that we’re trying to create a custom exception class, but we didn’t do it right.

04:23 It’s saying that our class must inherit from BaseException. BaseException is a built-in class provided for all error types. There are lots of classes that derive from BaseException, such as SyntaxError and ArithmeticError, which means that we can use them in place of BaseException.

04:47 Remember, if SyntaxError inherits from BaseException, it means SyntaxError is a BaseException because it inherits all of the members of BaseException. What specific exception type you inherit from depends on the situation at hand. BaseException is not supposed to be inherited from directly, so we’ll choose its next child, a class called Exception.

05:16 This is the class that the official documentation recommends inheriting from. I’ll redefine the MyError class, but this time I’ll put the name of the class I want to inherit from in parentheses, after the class name.

05:33 MyError is now an Exception, literally. I could write pass in here and leave the custom exception type blank,

05:42 but I want to do one more thing. Exceptions usually have some sort of message that’s intended to tell the user or developer what went wrong. The Exception class contains an attribute for the message,

05:57 and as such, it’s been passed down to our MyError class. To use it, we first must add an .__init__() method to this class. This exception will need to be passed a message when it is raised.

06:15 Now, we can use the super() function to call the .__init__() method of Exception,

06:22 passing in the message. In essence, when we create a MyError object, we’re asking for a message and then passing it to the parent.

06:33 Finally, now that we’re done writing our class, we can raise MyError, passing in whatever message we want. I’ll choose a particularly unhelpful one that you might’ve seen before.

06:47 There’s our custom exception with the message. This was possible due to inheritance. We created a custom class that inherited from Exception, so Python recognized our class as an exception.

07:02 We even utilized the inherited .message attribute to allow our custom exception class to be utilized with a custom message.

Avatar image for leilanobatova

leilanobatova on June 26, 2020

Austin said in video that link to the course about Exceptions will be under the video, I couldn’t find one. It would be super helpful to have one here. Thanks!

Avatar image for Subhash Bhushan

Subhash Bhushan on June 26, 2020

He could have been referring to this: realpython.com/courses/introduction-python-exceptions/

Avatar image for manohaard

manohaard on July 27, 2020

where can I find all your courses?? pls provide link..

Avatar image for Dan Bader

Dan Bader RP Team on July 27, 2020

You can click on an instructor’s name to see all of their courses. For example, all of Austin’s courses are listed here on his team profile: realpython.com/team/acepalia/

Avatar image for muondude

muondude on Jan. 13, 2022

I found this section on inheritance a bit hard to follow. Why did you not have to create an instance of MyError?

Avatar image for Bartosz Zaczyński

Bartosz Zaczyński RP Team on Jan. 13, 2022

@muondude He did create an instance of MyError by calling it with a pair of parentheses. Note that in Python, you can raise either an exception class or its instance:

>>> class MyError(Exception):
...     pass

>>> # Class:
>>> raise MyError
Traceback (most recent call last):
  File "<input>", line 1, in <module>
    raise MyError

>>> # Class instance:
>>> raise MyError("Details about the error...")
Traceback (most recent call last):
  File "<input>", line 1, in <module>
    raise MyError("Details about the error...")
MyError: Details about the error...

It makes sense to raise an instance of an exception class when you need to provide some context around the error that occurred.

Just curious, is it true to say that, to use the MyError class “we must” add .__init__()? Without it, wouldn’t it just use .__init__() in the parent class anyway?

Avatar image for Bartosz Zaczyński

Bartosz Zaczyński RP Team on April 26, 2023

@malcolmperfect You’re right. Technically, you don’t have to implement your own .__init__() method in a subclass unless you want to change its paramater list or modify the behavior somehow. The following code will work just fine:

>>> class MyError(Exception):
...     pass
>>> MyError("Something went wrong")
MyError('Something went wrong')

Become a Member to join the conversation.