Inheritance¶
Basic Inheritance¶
Python classes support inheritance. Inheritance in computer science is an “is-a” relationship. For example, a dog is an animal. If we defined a class Animal, then we could also define a subclass Dog, that inherits the data and methods of its parent class, Animal. The parent class is also often referred to as the superclass.
To use inheritance, we can make a subclass. Let’s make a NamedAccount class which subclasses our BankAccount class:
class NamedAccount(BankAccount):
"""Bank account with an account name."""
def __init__(self, *args, **kwargs):
"""Open a named bank account."""
self.name = kwargs.pop('name', None)
super().__init__(*args, **kwargs)
def print_balance(self):
"""Print the account name and current account balance."""
print('Account "{}" balance is ${}'.format(self.name, self.balance))
def __str__(self):
"""Return account name and balance."""
return 'Account "{name}" with balance of ${balance}'.format(
name=self.name,
balance=self.balance,
)
def __repr__(self):
"""Return developer-readable representation of our named account."""
return 'NamedAccount(balance={balance}, name={name})'.format(
balance=self.balance,
name=repr(self.name),
)
The special super function allows us to call methods from parent classes. In our __init__ method we popped the argument name from the keyword argument dictionary, because that is the only one we are using in our method. Then the other arguments are passed on to the __init__ method of the parent class.
Right now there is only one other argument for the BankAccount class. Catching *args and **wkargs and passing them on to the super class ensures that nothing will break if the BankAccount class changes the arguments it accepts.
Now let’s confirm that our class methods work as expected:
>>> from bank_account import NamedAccount
>>> nameless_account = NamedAccount()
Account opened.
Account "None" balance is $0
>>> nameless_account
NamedAccount(balance=0, name=None)
>>> nameless_account.name
>>> nameless_account.name is None
True
>>> trey_account = NamedAccount(name="Trey")
Account opened.
Account "Trey" balance is $0
>>> trey_account.name
'Trey'
>>> trey_account
NamedAccount(balance=0, name='Trey')
Because NamedAccount is a subclass of BankAccount, we can also use the methods of BankAccount on the NamedAccount objects:
>>> trey_account.deposit(45)
$45 deposited.
Account "Trey" balance is $45
>>> trey_account.deposit(145)
$145 deposited.
Account "Trey" balance is $190
>>> trey_account.withdraw(25)
$25 withdrawn.
Account "Trey" balance is $165
Note that because the methods were implemented using the print_balance method, we get the account name printed when the balance is printed after the transaction is completed. This is because the subclass definition of a method overrides the parent class’s definition. When Python sees a method call on an object, it looks for the method on the object first and only checks base classes afterward.
Multiple Inheritance¶
Python also allows for multiple inheritance. This means that a class can have multiple base classes. This feature is somewhat advanced and understanding how super works in this scenario is a little tricky.
We can see that one class can inherit from two classes like this:
>>> class Cat:
... def meow(self):
... print("meow")
...
>>> class Robot:
... def beep(self):
... print("boop")
...
>>> class RoboCat(Robot, Cat):
... def meow(self):
... super().meow()
... print("I am a robot")
...
>>> leo = RoboCat()
>>> leo.meow()
meow
I am a robot
>>> leo.beep()
boop
We will not be discussing inheritance very deeply during this course.
Inheritance Exercises¶
Minimum Balance¶
Create a class MinimumBalanceAccount which subclasses BankAccount. This new class should raise an exception whenever the user attempts to withdraw so much money that their account goes below 0.
>>> from bank_account import MinimumBalanceAccount
>>> my_account = MinimumBalanceAccount()
Account opened.
Account balance is $0.
>>> my_account.deposit(100)
$100 deposited.
Account balance is $100.
>>> my_account.withdraw(200)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "bank_account.py", line 45, in withdraw
raise ValueError("Balance cannot be less than $0!")
ValueError: Balance cannot be less than $0!