Multiple Inheritance Example#
Let’s look at a complete example of multiple inheritance using the bank account context.
In this example we create a “Premium Savings Account” class
PremiumSavingsAccount, which combines savings account functionality with a
rewards point system by inheriting from two classes, each responsible for
different functions.
Note
You can click the above image to expand it!
Base and Savings Accounts#
These classes should look familiar from earlier examples. The
SavingsAccount class inherits from BaseAccount and adds a basic
interest calculation method.
Rewards Account#
The RewardsAccount class is a “mixin” and is independent from any other
class. It overrides the deposit method to add rewards points each time a
deposit is made.
Premium Savings Account#
The PremiumSavingsAccount only needs to inherit from the SavingsAccount
and RewardsAccount classes as they already implement the required
functionality. Because of the multiple inheritance we have to manually call the
constructors of parent classes.
The order of the inheritance is critical for the deposit functionality to work because of the MRO.
class PremiumSavingsAccount(RewardsAccount, SavingsAccount):
If we swapped the order, then SavingsAccount.deposit would be called
instead of RewardsAccount.deposit when using PremiumSavingsAccount.
It’s important to note that we are treating the constructors as normal
functions and need to manually pass self:
SavingsAccount.__init__(self, bsb_number, account_number, balance, holder_name, interest_rate)
RewardsAccount.__init__(self) # Initialize the rewards system
class BaseAccount:
def __init__(self, bsb_number, account_number, balance, holder_name):
self.bsb_number = bsb_number
self.account_number = account_number
self.balance = balance
self.holder_name = holder_name
def deposit(self, amount):
self.balance += amount
def withdraw(self, amount):
self.balance -= amount
class SavingsAccount(BaseAccount):
def __init__(self, bsb_number, account_number, balance, holder_name, interest_rate):
super().__init__(bsb_number, account_number, balance, holder_name)
self.interest_rate = interest_rate
def get_earned_interest(self):
return self.balance * self.interest_rate
class RewardsAccount:
def __init__(self):
self.reward_points = 0
def add_rewards(self, amount):
points_earned = amount * 0.1 # 1 point per $10 deposited
self.reward_points += points_earned
def deposit(self, amount):
super().deposit(amount) # Call the deposit method from BaseAccount
self.add_rewards(amount) # Also apply rewards system
class PremiumSavingsAccount(RewardsAccount, SavingsAccount):
def __init__(self, bsb_number, account_number, balance, holder_name, interest_rate):
SavingsAccount.__init__(
self, bsb_number, account_number, balance, holder_name, interest_rate
)
RewardsAccount.__init__(self) # Initialize the rewards system
# Example Usage
premium_acc = PremiumSavingsAccount("689716", "62228626", 19.39, "Bruce Wayne", 0.0235)
premium_acc.deposit(500) # Adds money and rewards points
print("Interest Earned:", premium_acc.get_earned_interest()) # Check interest
print("Total Reward Points:", premium_acc.reward_points) # Check rewards points
Code Challenge: Awesome Ship
Note
For this exercise you should have completed Super > “Attack Ship”, Hierarchical Inheritance > “Infinite Cargo Ship” and Multilevel Inheritance > “Shield Up”
You think to yourself “Why have we been making separate ships with different abilities?” What about a ship with everything?!
Make an AwesomeShip class that adds the torpedo rounds from the attack ship, infinite cargo capacity and defensive shields.
The AwesomeShip class should inherit from the following independent classes in order:
Spaceshipas providedAttackShipas providedShieldedShipInfiniteCargoShip
so that all the functionality is available and working aboard the ship
ShieldedShip Specifications
Attributes
shield_level
__init__method withParameters
self
Actions
Set the
shield_levelto 100
damagemethod withParameters:
selfamount
Actions:
Reduces the shield level by the given amount down to
0.
Returns:
None(no return statement required)
rechargemethod withParameters:
self
Actions:
Resets the shield level to
100
InfiniteCargoShip Specifications
Attributes:
cargo_volumeas described above
__init__method withParameters:
selfnamefuel_capacity
Actions:
Call the Spaceship constructor to set common attributes with the same name
Set the
cargo_volumeattribute to0
load_cargomethod withParameters
selfvolume
Actions
Increase the
cargo_volumeby the given volume
unload_cargomethod withParameters
selfvolume
Actions
Reduce the
cargo_volumeby the given volume down to0.
AwesomeShip Specifications
Inherit from
Spaceshipas providedAttackShipas providedShieldedShipInfiniteCargoShip
__init__method withParameters:
selfnamefuel_capacityrounds
Actions:
Call all parent class constructors
Here is some code for you to start with:
class Spaceship:
def __init__(self, name, fuel_capacity):
self.name = name
self.fuel_weight = 0
self.fuel_capacity = fuel_capacity
def refuel(self, weight):
if self.fuel_weight + weight > self.fuel_capacity:
self.fuel_weight = self.fuel_capacity
else:
self.fuel_weight += weight
def fire_laser(self):
if self.fuel_weight >= 10:
self.fuel_weight -= 10
class AttackShip():
def __init__(self, rounds):
self.rounds = rounds
def fire_round(self):
if self.rounds > 1:
self.rounds -= 1
# ADD YOUR CLASSES HERE
class AwesomeShip(Spaceship, AttackShip):
def __init__(self, name, fuel_capacity, rounds):
Spaceship.__init__(self, name, fuel_capacity)
AttackShip.__init__(self)
Solution
Solution is locked