<jupyter_start><jupyter_text>Inheritance between classesWhen you start working with objects, at times you want to call one object from another object. That would make it easy to have 2 independent objects work great by themselves (and be debugged simply), and have one object use the other as required.  At first glance, this would look like:<jupyter_code>class Person:
    """
    The person class has a name (2 variables) and has 2 methods
    """
    def __init__(self, first, last):
        self.firstname = first
        self.lastname = last

    def Name(self):
        return self.firstname + " " + self.lastname
    
    def Fart(self):
        print("... oops {} farted...".format(self.firstname))<jupyter_output><empty_output><jupyter_text>Testing this class we see that it works quite simply<jupyter_code>x = Person("Homer", "Simpson")
x.Name()
x.Fart()<jupyter_output>... oops Homer farted...<jupyter_text>Now we can have another class that calls -- call it `Employee` -- that *formally* uses the `Person` class<jupyter_code>class Employee:

    def __init__(self, first, last, staffnum):
        self.p = Person(first, last)
        self.staffnumber = staffnum

    def GetEmployee(self):
        return self.p.Name() + ", " +  str(self.staffnumber)
y = Employee("Homer","Simpson",1023)
y.GetEmployee()<jupyter_output><empty_output><jupyter_text>Notice that to call the `.Name()` method, we have to first specify `self.p` -- as the original `Person` object is saved as this variable!In other words, by assignign `p = Person()`, its methods are not availible in the `Employee` object, but nested in the variable!![classes_inheritance1.PNG](../imgs/classes_inheritance1.PNG)![classes_inheritance2.PNG](../imgs/classes_inheritance2.PNG)  Another way would be to use inheritance<jupyter_code>class Employee(Person):

    def __init__(self, first, last, staffnum):
        Person.__init__(self, first, last)
        self.staffnumber = staffnum

    def GetEmployee(self):
        return self.Name() + ", " +  str(self.staffnumber)
y = Employee("Homer","Simpson",1023)
y.Fart()<jupyter_output>... oops Homer farted...<jupyter_text>If we use inheritance, the `Employee` object has all methods and variables availible from the `Person`:![classes_inheritance3.PNG](../imgs/classes_inheritance3.PNG)  If your child method doesnt use `__init__()`, then all methods are automatically inheritedRemember how we specified `Person.__init__()` in our `Employee.__init__()` method?```python    def __init__(self, first, last, staffnum):        Person.__init__(self, first, last)```Well we only need to do that if the child method has an `__init__()` method!<jupyter_code>class Cartoon(Person):
    
    def Jump(self):
        print(self.Name(), 'jumped!!')
homer = Cartoon("Homer","Simson")
homer.Jump()<jupyter_output><NAME> jumped!!
{'fraction_non_alphanumeric': 0.12084805653710247, 'fraction_numerical': 0.006007067137809187, 'mean_word_length': 4.311444652908068, 'pattern_counts': {'":': 0, '<': 19, '<?xml version=': 0, '>': 19, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '5', 'dir': 'jupyter-structured-clean-dedup', 'id': '599814', 'license': 'MIT', 'n_tokens_mistral': 899, 'n_tokens_neox': 855, 'n_words': 273, 'path': 'walkthroughs/classes_and_inheritance.ipynb', 'repo_name': 'sergegoussev/training_and_experiments', 'size': '2836'}