Example code - Inheritance issues
The challenges in inheritance can not be demonstrated well in a powerpoint. Thus, I made this page with examples. You can copy the code in the section and add it together and run it.
First I create a slightly bigger CatClass.
class CatClass:
### Class variables
genus = "Felis"
species = "Catus"
acts = {'scratch': "purrs",
'scare': "jumps high in the air",
'feed': "is very excited" }
### Instatiation
def __init__(self, name, gender):
self.name, self.gender = name, gender
### Magic methods
# Addition makes a kitten if male and female cat, alternative constructor
def __add__(self, other):
# Taken a short cut and just demanding the genders to be different to breed
if self.gender == other.gender:
return NotImplemented
# Being biased and saying all kittens are male
kitten = CatClass('Unnamed kitten', 'male')
return kitten
### Class methods
# Adding a cat action
@classmethod
def add_action(cls, action, reaction):
cls.acts[action] = reaction
# Querying class for number of actions
@classmethod
def count_action(cls):
return len(cls.acts)
### Property methods
# age setter and getter
@property
def age(self):
if not hasattr(self, '_age'):
raise NameError("Age of cat is not yet set")
return self._age
@age.setter
def age(self, value):
if value < 0:
raise ValueError("Age can not be negative")
self._age = value
### Instance methods
# The action method - using class variables
def action(self, act):
if act in CatClass.acts:
print(self.name, CatClass.acts[act])
elif self.gender == 'male':
print(self.name, "looks bored")
else:
print(self.name, "yawns")
### Main program
yourcat = CatClass('Missy', 'female')
yourcat.age = 5
print(f"The age of your cat is {yourcat.age}")
CatClass.add_action("annoy", "scratches your face")
print("Actions in CatClass:", CatClass.count_action())
mycat = CatClass("Tom", "male")
kitten = mycat + yourcat
print(f"Kitten: {kitten.name}")
yourcat.action('scare')
This class looks fine, but it has a number of inheritance issues. By creating a Tiger class that inherits from the CatClass, I will demonstrate. Also, see how simple it was to create a new class based on an old :-)
class Tiger(CatClass):
acts = {
'scratch': 'roars',
'feed': 'demands more meat'
}
tigger = Tiger("Shere Khan", "male")
tigger.action("scratch")
tigger.action('scare')
We want the Tiger to react differently than the Cat, at least for some actions. However, this code does not do it. The problem lies in the inherited action method.
def action(self, act):
if act in CatClass.acts:
print(self.name, CatClass.acts[act])
elif self.gender == 'male':
print(self.name, "looks bored")
else:
print(self.name, "yawns")
# We are specifically using the actions in the CatClass for the behavior
# We need to use the current class, as in cats uses CatClass actions and tigers uses Tiger actions.
# These are the problematic lines, they can be replaced in different ways
if act in CatClass.acts:
print(self.name, CatClass.acts[act])
# Through '''self''', as self will search the instance namespace and then the class namespace for the variable
if act in self.acts:
print(self.name, self.acts[act])
# By dynamically getting the class by type
cls = type(self)
if act in cls.acts:
print(self.name, cls.acts[act])
This does not completely solve the problem. We would still like to be able to scare the tiger (inherit the cat action), but for now it looks bored when we try. This problem is caused by the complete replacement of the class variable acts in the Tiger class. The cat actions are deleted and replaced with tiger-only actions.
class Tiger(CatClass):
acts = {
'scratch': 'roars',
'feed': 'demands more meat'
}
# Thats OK, we will just add the tiger actions later - we inherited the add_action from CatClass
class Tiger(CatClass):
pass
tigger = Tiger("Shere Khan", "male")
tigger.add_action('scratch', 'roars')
tigger.add_action('feed', 'demands more meat')
# Testing
tigger.action('scare')
tigger.action('feed')
# All good, but what happened to our cat?
mycat.action('scratch')
The cat started roaring when scratched - that is a tiger action. Looking at the add_action class method, it is not specifying anywhere that the CatClass should be used so what is wrong?