Skip to main content

Getting started with classes in Python Part 10: Inheritance

james.derrick@ansys.com | 04.02.2025

Getting started with classes in Python Part 10: Inheritance

We're nearly at the end of the journey (for now)! This is the tenth article about getting started with Python classes on the Ansys developer portal and it is actually about one of the least important concepts from a day-to-day perspective but one of the most important from a theoretical stand point: inheritance. In general I would recommend avoiding inheriting from classes when you are a beginner and I don't intend to go into the details around how you can make use of it because that is largely too advanced for this series. Instead I will focus on the concept of 'subclassing' and inheriting because it is something you should understand conceptually, even if you don't know how to do it yourself!

What is "inheritance" in a programming context?

Inheritance is the method used to extend and alter existing classes. Suppose you have created an Animal class and want to now use it as a template to create a Cat class? However, you notice that you're really repeating all of the same properties but just adding additional logic pertaining to cats; surely there's a way to do it without repeating yourself? This is where inheritance comes in. Instead of copying the Animal class you can inherit it!

You may be thinking "why don't I just go and edit a class if I want to change its behaviour?" and you'd be right to think that, but a compounding factor is that often you aren't working with classes that you wrote, or the original class can't be altered because something else in your code relies on it not changing. In the example above, the Animal class may come from an external package. In situations like this you can create a new class that "inherits" from the original and edit that. This is also known as "subclassing" a class. Inherited classes can access all the properties and methods of the parent class as well as any additional functionality you choose to add.

Example: booleans and integers in Python

This technique is used a lot in professional development and there's a lot of debate about whether or not this is a good thing. My go-to example is that booleans in Python (True and False) actually inherit from integers. Python booleans can be treated as integers.

For example, you can add booleans and integers together.

x = True + 1
print(x)

This code will print 2 because True is 1 and False is 0 in Python. The boolean class still retains the integer properties due to the inheritance.

What does inheritance look like in Python?

First of all, we have been considering dataclasses predominantly in this series, but I do not recommend inheriting dataclasses into other dataclasses. This does not work as easily as you might think it should and the problem is actually a known issue due to how default arguments work. It's all to do with how they're constructed. If you want to do that anyway there's an excellent article about why it's a problem and how to fix it on Medium called Python dataclass inheritance, finally!, which I recommend you read.

Otherwise class inheritance syntax looks like the following. Suppose we have a simple dataclass called Point that stores a pair of (x, y) coordinates and we want to subclass this into a new class called Coordinate which also stores a z coordinate. This is what we would write.

from dataclasses import dataclass


@dataclass
class Point:
    x: int
    y: int


class Coordinate(Point):
    def __init__(self, x: int, y: int, z: int):
        super().__init__(x, y)
        self.z: int = z

    def __repr__(self):
        return f'Coordinate(x={self.x}, y={self.y}, z={self.z})

c = Coordinate(1, 2, 3)
print(c)

Which outputs.

Coordinate(x=1, y=2, z=3)

This looks fine! There are only two things here that we haven't seen in the article series so far. First is that subclassing works by providing the parent class name in parentheses at the initial declaration, like we would do parameters for a function or a method. The second is somewhat stranger and is the use of super(). super is a built-in function that allows you to access the parent class and its methods, even if they have been overwritten in the inherited class. If that sounds a bit complicated I recommend reading the docs here, "Python docs, super", for more information. Essentially, super() let's us instantiate the parent class with its __init__, even though we have technically overwritten it, which means we can avoid writing our own for both.

Some Advanced Features

Inheritance may seem like a simple feature but it is actually quite powerful and very useful day-to-day with a few quality-of-life features that are available in Python. For example, Python will let you subclass classes that aren't complete on their own, but have useful features. "Abstract Base Classes", or ABCs, are an example of this. They are classes that can't be instantiated on their own but when inherited provide many useful methods and properties that are normally a chore to construct. You can also use the builtin package to construct your own abstract base classes, and make methods that remain undefined until they are inherited and overwritten in the subclass, like a 'class blueprint'.

There are quite a few builtin base classes that you can import. One we have used in the series already but not explained is Enum, which allows us to create an Enum type class.

from enum import Enum


class Direction(Enum):
    NORTH = 1
    WEST = 2
    EAST = 3
    SOUTH = 4

This syntax is not possible without this inheritance. We can even use inheritance to subclass collections like lists and dictionaries and develop our own versions with unique properties, although I wouldn't recommend it as that comes with it's own host of problems. See Trey Hunner's great article on the matter for more information Why You Shouldn't Inherit From List and Dict in Python.

Finally I want to touch on one last feature of subclassing, which is that you can actually subclass multiple classes simultaneously. This is, however, a very advanced feature that is not present in many other programming languages. I do not recommend tackling it unless you know what you're doing, but it is something you should know can be done. If you want to know more still I recommend reading Real Python's Guide to Inheritance and Composition in Python because they do a fantastic job of explaining the matter in great detail.

Conclusion

And that's it! I haven't gone into much depth about inheritance here because that could easily warrant another ten-part series on the topic and this piece should make it clear why inheritance exists, what it's used for and what it looks like, but not be a detailed guide about how to use it.

And with that, this series is concluded. I hope to write more about Python in the future but this should be a comprehensive overview of the basics of classes for anyone just getting started with them and also plug the gap in the Introduction to Python where they are conspicuously absent. if you have read all the way through to Part 10, thank you for your time, I hope you've enjoyed it and I hope you were able to get some useful tips and tricks out of this. I hope to write about more useful features of Python in the future so please stay tuned to see that and if you have any comments, or questions, about the article series head over to the Ansys Developer Forum and the General Language Questions category where I'd be happy to answer any questions you might have.