Computer >> Computer tutorials >  >> Programming >> Python

Python Inheritance: A Step-By-Step Guide

Python inheritance is when a subclass uses the code from another class. Inheritance is an essential feature in object-oriented languages like Python that makes coding easier and more efficient.


Python is an object-oriented language, which means that it supports creating reusable blocks of code to help make code more efficient. One of the ways in which this happens is through inheritance, where one subclass can use code from another class.

For example, you may have a class that stores “bank accounts”, and want to create a subclass that stores “gold bank accounts” that can reference attributes in the “bank accounts” existing class.

In this tutorial, we are going to break down the basics of inheritance in Python. We are also going to discuss how parent and child Python classes work, and how to override attributes and methods when you’re working with classes objects.

Python Inheritance

Inheritance is a term that is used to describe a Python class within another class. Classes called subclasses or child classes can inherit values from parent classes, similar to how children inherit characteristics from their parents in the real world.

Inheritance is useful because it allows us to create subclasses that have the same value types as a parent class, without having to declare those types multiple times.

Parent Classes

Parent classes (also called base classes create the master structure that subclasses can access. We can create multiple subclasses without having to declare the same set of common values over again that derived class methods from the parent class.

Let’s use an example to illustrate how this would work in action. Say that we had a program that works with two different bank account types: parent and child.

81% of participants stated they felt more confident about their tech job prospects after attending a bootcamp. Get matched to a bootcamp today.

The average bootcamp grad spent less than six months in career transition, from starting a bootcamp to finding their first job.

Both of these accounts are bank accounts, and so they will have similar values. But each of these accounts may require their own unique information. For example, a parent’s account may support an overdraft, whereas the child’s account may only work with their balance.

So, if we wanted to create a program with these values, we would first define a class for our bank account (a parent class) then create child classes for the two types of bank accounts—parent and child—that we want to support.

Here’s an example of declaring a parent class for a bank account:

class BankAccount:
	def __init__(self, forename, surname, balance):
		self.forename = forename
		self.surname = surname
		self.balance = balance

We have created the class BankAccount which stores three values: forename, surname, and balance. We can also add methods to our class, like so:

class BankAccount:
	def __init__(self, forename, surname, balance):
		self.forename = forename
		self.surname = surname
		self.balance = balance

	def getDetails(self):
		print("Forename: ", self.forename)
		print("Surname: ", self.surname)

	def getBalance(self):
		print("Balance: $ ", self.balance)

Our class now stores three values, as well as two new methods: details and balance. The details method can be used to find out our account holder’s forename and surname, and the balance method will return the account holder’s balance.

Every method and variable that we declare in our BankAccount class will be accessible in our child class.

To illustrate our class in action, let’s create an example bank account. We can do so using the following code:

account = BankAccount("John", "Appleseed", 100)

This will create an account for John Appleseed which contains $100. Now that we have our account ready, we can start to reference it like we would with any other class. Here’s an example of us running the getBalance() method within our bank account to find out how much money we have:

print(account.getBalance())

Our program returns the following:

Balance: $ 100

Child Classes

In the above example, we declared a parent class which stores bank accounts. But what if we want to store information about a specific type of account like a child’s under 18 account? That’s where child classes come in.

Child classes, or subclasses, inherit values from the parent class. This means that each child class will be able to reference the methods and variables that we declare in our parent class.

So, let’s say that we want to create a child class for a ChildBankAccount. This account should be able to return a user’s bank account information—their name and balance—and should also have a new value called restricted. This value will be stored on a child’s account because they are under 18, and are not eligible for a full bank account.

In order to create a child class, we can use the following code:

class ChildBankAccount(BankAccount):

The ChildBankAccount class becomes a child of the BankAccount class because BankAccount is enclosed within parentheses. If we want our child class to have exactly the same values as our parent class—BankAccount—we can use the pass keyword like this:

class ChildBankAccount(BankAccount):
	pass

But as we discussed earlier, our child account will need to store a special value: a variable that says that the user’s account is restricted.

To accomplish this goal, we are going to add a new value called restricted to our child class. We can do this using the following code:

class ChildBankAccount(BankAccount):
	def __init__(self, forename, surname, balance, restricted=True):
self.forename = forename
self.surname = surname
self.balance = balance
self.restricted = restricted

	def isRestricted(self):
		print("This account is restricted as the user is under 18.")

Now, let’s break down our code.

In the above code, we state that we want our ChildBankAccounts to hold four values: forename, surname, balance, and restricted.

The first three—forename, surname, and balance—are the same as our parent class values but restricted is new, and it is exclusive to our child class. By default, restricted is set to True.

So if we create a standard BankAccount (not a ChildBankAccount), we will not be able to access the restricted value. Similarly, we won’t be able to access the isRestricted method unless we create a ChildBankAccount.

Here’s an example of us creating a ChildBankAccount and using the getBalance() and isResticted() methods to learn more about our class:

child_account = ChildBankAccount("Bill", "Appleseed", 100) 
print(child_account.getBalance())
print(child_account.isRestricted())

Our code returns the following:

Balance: $ 100
This account is restricted as the user is under 18.

As you can see, our program first defines a new ChildBankAccount for Bill Appleseed, whose account holds $100. Then, our program executes the getBalance() method in our class, which returns the user’s balance. getBalance() is declared in our parent class, BankAccount, but is accessible to ChildBankAccount through inheritance.

Our program also executes the isRestricted() method, which states that the child’s account is restricted because they are under the age of 18. This class is declared in ChildBankAccount, though, which means that it is not accessible to our parent class BankAccount. If we wanted to create a restricted BankAccount, we would need to change the parent class.

Redefining Parent Methods

In our above example, we declared a parent class called BankAccount which stores information for bank accounts. We also created a child class called ChildBankAccount which stores information for account holders under the age of 18. This class inherited the methods from the BankAccount class and also created the isRestricted() method.

But what if we want to modify an existing parent class method? Say we want our BankAccount balance to return a message with their balance and a message stating You are eligible for an overdraft, but we don’t want this to appear for ChildBankAccount holders.

To do this, we need to override our parent method.

Here’s the code for our revised parent method, BankAccount, which now prints a message to account holders to say they are eligible for an overdraft when they check their balance:

class BankAccount:
	def __init__(self, forename, surname, balance):
		self.forename = forename
		self.surname = surname
		self.balance = balance

	def getDetails(self):
		print("Forename: ", self.forename)
		print("Surname: ", self.surname)

	def getBalance(self):
		print("Balance: $ ", self.balance)
		print("You are eligible for an overdraft.")

Now, if we create a new BankAccount for John Appleseed and print out his balance, we’ll see a message stating You are eligible for an overdraft. Here’s an example of us declaring a new account and checking its balance:

account = BankAccount("John", "Appleseed", 100)
print(account.getBalance())

Our code returns the following:

Balance: $ 100
You are eligible for an overdraft.

But this change also means that our ChildBankAccount, which inherits its values from BankAccount, will also see the message. Here’s an example of us creating a ChildBankAccount and checking its balance now that our BankAccount parent class has changed:

child_account = ChildBankAccount("Bill", "Appleseed", 100) 
print(child_account.getBalance())

Our code returns:

Balance: $ 100
You are eligible for an overdraft.

Because children are generally not allowed overdrafts, we will need to make a change to our code. Now, in order to do so, we have to modify our ChildBankAccount class and declare a new getBalance() function.

Here’s the code for our ChildBankAccount from above:

class ChildBankAccount(BankAccount):
	def __init__(self, forename, surname, balance, restricted=True):
self.forename = forename
self.surname = surname
self.balance = balance
self.restricted = restricted

	def isRestricted(self):
		print("This account is restricted as the user is under 18.")

We need to change this code to add a new function: getBalance(). This function will work in the same way as the one we declared in our parent class, but it will not include the message about overdrafts. Here’s the code that we would add to declare our new function:

…

def getBalance(self):
 print("Balance: $ ", self.balance)

Let’s try to retrieve our child’s balance now:

child_account = ChildBankAccount("Bill", "Appleseed", 100) 
print(child_account.getBalance())

Our code returns the following:

Balance: $ 100

In the above example, we have overwritten the getBalance() method in the ChildBankAccount child class. Our new getBalance() method for ChildBankAccount only shows the user’s balance. But in our BankAccount class, the getBalance() method shows both the user’s balance and the message You are eligible for an overdraft.

Overriding parent methods can be useful when you have multiple child methods which may use similar methods to their parents, but require their own specific changes to be made. Like in the case above, we want our parent bank accounts to see an overdraft message, but not our child bank accounts, so we overrode our parent method in ChildBankAccount.

Conclusion

Inheritance is used in object-oriented programming to help you create subclasses that can store values already declared in a parent class. This is useful when you are creating similar classes that will store similar values because you can use inheritance to create those classes without repeating your code multiple times over.

In this tutorial, we explored the role of inheritance in Python. We also discussed how inheritance and parent and child classes work, then we explored how to override parent methods. Now you’re ready to work with classes and inheritance like a Python expert!