Example code - Inheritance issues: Difference between revisions

From 22118
Jump to navigation Jump to search
mNo edit summary
mNo edit summary
Line 99: Line 99:


     # We are specifically using the actions in the CatClass for the behavior
     # We are specifically using the actions in the CatClass for the behavior
     # We need to use the current class, as in cat uses CatClass actions and tigers uses Tiger actions.
     # 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
     # These are the problematic lines, they can be replaced in different ways
         if act in CatClass.acts:
         if act in CatClass.acts:
             print(self.name, CatClass.acts[act])
             print(self.name, CatClass.acts[act])
     # Through '''self''', as self will search for the instance namespace and then the class namespace for the variable
     # Through '''self''', as self will search the instance namespace and then the class namespace for the variable
         if act in self.acts:
         if act in self.acts:
             print(self.name, self.acts[act])
             print(self.name, self.acts[act])
     # Dynamically getting the class by type
     # By dynamically getting the class by type
         cls = type(self)
         cls = type(self)
         if act in cls.acts:
         if act in cls.acts:
             print(self.name, cls.acts[act])
             print(self.name, cls.acts[act])
</pre>
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.
<pre>
class Tiger(CatClass):
    acts = {
        'scratch': 'roars',
        'feed': 'demands more meat'
    }
# By changing instead of replacing we might get somewhere good.
class Tiger(CatClass):
    acts['scratch'] = 'roars'
    acts['feed'] = 'demands more meat'
</pre>
</pre>

Revision as of 17:37, 19 March 2026

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'
    }

# By changing instead of replacing we might get somewhere good.
class Tiger(CatClass):
    acts['scratch'] = 'roars'
    acts['feed'] = 'demands more meat'