<jupyter_start><jupyter_text>Introduction to object oriented programming (OOP)This is a notebook (independent of SIRF) that was used during a presentation given by <NAME> for CCP PETMR in 2017.Please watch the [recording](http://www.ccpsynerbi.ac.uk/sites/www.ccppetmr.ac.uk/files/Introduction_to_OOP_20170728.mp4) (note that the first 4 minutes are sound only, but screen sharing was then enabled). You can also download the corresponding [slides](http://www.ccpsynerbi.ac.uk/sites/www.ccppetmr.ac.uk/files/20170728_OOP_slides.pdf).Author: <NAME>Copyright (C) 2017 University College LondonSPDX-License-Identifier: Apache-2.0  Person```pythonclass Person:        constructor    def __init__(self,firstname,surname,age,job,gender):        self.firstname = firstname        self.surname = surname        self.age = age        self.job = job        self.gender = gender            def name(self):        return self.firstname + " " + self.surname```<jupyter_code>class Person:
   
    # constructor
    def __init__(self,firstname,surname,age,job,gender):
        self.firstname = firstname
        self.surname = surname
        self.age = age
        self.job = job
        self.gender = gender
        
    def name(self):
        return self.firstname + " " + self.surname
me = Person("Ben", "Thomas", 33, "PDRA", "male")
print(me)
#show name and age
print(me.age)
print(me.name())<jupyter_output><empty_output><jupyter_text>Encapsulation```pythonclass Person:        constructor    def __init__(self,firstname,surname,job,gender):        self.firstname = firstname        self.surname = surname        self.job = job        self.gender = gender        self.__age = -1        def name(self):        return self.firstname + " " + self.surname        def set_age(self,age):        self.__age = age            def get_age(self):        return self.__age```<jupyter_code>class Person:
   
    # constructor
    def __init__(self,firstname,surname,job,gender):
        self.firstname = firstname
        self.surname = surname
        self.job = job
        self.gender = gender
        self.__age = -1
    
    def name(self):
        return self.firstname + " " + self.surname
    
    def set_age(self,age):
        self.__age = age
        
    def get_age(self):
        return self.__age
me = Person("Ben", "Thomas", "PDRA", "male")
me.get_age()
me.set_age(33)
me.get_age()
me.__age<jupyter_output><empty_output><jupyter_text>Pythonic way```pythonclass Person:        Constructor    def __init__(self,firstname,surname,job,gender):        self.firstname = firstname        self.surname = surname        self.job = job        self.gender = gender        self.myrealage = -1        def name(self):        return self.firstname + " " + self.surname        @property    def age(self):        return self.myrealage    @age.setter    def age(self,value):        if 18 <= value <= 100:            self.myrealage = value        else:            raise ValueError("age must be between 18 and 100!")```<jupyter_code>class Person:
   
    # Constructor
    def __init__(self,firstname,surname,job,gender):
        self.firstname = firstname
        self.surname = surname
        self.job = job
        self.gender = gender
        self.myrealage = -1
    
    def name(self):
        return self.firstname + " " + self.surname
    
    @property
    def age(self):
        return self.myrealage

    @age.setter
    def age(self,value):
        if 18 <= value <= 100:
            self.myrealage = value
        else:
            raise ValueError("age must be between 18 and 100!")
me = Person("Ben", "Thomas", "PDRA", "male")
me.age = 33
me.age
me.age = 500<jupyter_output><empty_output><jupyter_text>Inheritance```pythonclass Animal:     Constructor    def __init__(self, name):                 Name attribute        self.name = name        def show_info(self):        print("My name is " + self.name)class Cat(Animal):        def __init__(self, name, food):                 Call the parent constructor to set name.        super().__init__(name)                 Set the 'likes' variable.        self.likes = food```<jupyter_code>class Animal:
    # Constructor
    def __init__(self, name):
        
        # Name attribute
        self.name = name
    
    def show_info(self):
        print("My name is " + self.name)
class Cat(Animal):
    
    def __init__(self, name, food):
        
        # Call the parent constructor to set name.
        super().__init__(name)
        
        # Set the 'likes' variable.
        self.likes = food
tom = Cat("Tom", "fish")
tom.show_info()<jupyter_output><empty_output><jupyter_text>Adapt the child class```pythonclass Cat(Animal):    def __init__(self, name, food):         Call the parent constructor to set name.        super().__init__(name)         Set the 'likes' variable.        self.likes = food    def show_info(self):         Call parent show_info        super().show_info()         Print info from child        print("I like eating " + self.likes)```<jupyter_code>class Cat(Animal):

    def __init__(self, name, food):
        # Call the parent constructor to set name.
        super().__init__(name)

        # Set the 'likes' variable.
        self.likes = food

    def show_info(self):
        # Call parent show_info
        super().show_info()
        # Print info from child
        print("I like eating " + self.likes)
tom = Cat("Tom", "fish")
tom.show_info()<jupyter_output><empty_output><jupyter_text>Polymorphism and abstract classes```pythonclass Animal:     Constructor    def __init__(self, name):                 Name attribute        self.name = name        def show_surface(self):        raise NotImplementedError("Must implement abstract method")        class Cat(Animal):        def show_surface(self):        print(self.name + " has fur")class Dog(Animal):        def show_surface(self):        print(self.name + " has fur")class Duck(Animal):        def show_surface(self):        print(self.name + " has feathers")```<jupyter_code>class Animal:
    # Constructor
    def __init__(self, name):
        
        # Name attribute
        self.name = name
    
    def show_surface(self):
        raise NotImplementedError("Must implement abstract method")
class Cat(Animal):
    
    def show_surface(self):
        print(self.name + " has fur")

class Dog(Animal):
    
    def show_surface(self):
        print(self.name + " has fur")

class Duck(Animal):
    
    def show_surface(self):
        print(self.name + " has feathers")
c = Cat("Tom")
p = Dog("Pluto")
d = Duck("Donald")
pets = [c,p,d]
for pet in pets:
    pet.show_surface()<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.11208195239529979, 'fraction_numerical': 0.009189514914130762, 'mean_word_length': 2.516419491525424, 'pattern_counts': {'":': 0, '<': 31, '<?xml version=': 0, '>': 27, 'https://': 0, 'lorem ipsum': 0, 'www.': 4, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 1, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '6', 'dir': 'jupyter-structured-clean-dedup', 'id': '106925', 'license': 'Apache-2.0', 'n_tokens_mistral': 2087, 'n_tokens_neox': 1967, 'n_words': 502, 'path': 'notebooks/Introductory/object_oriented_programming.ipynb', 'repo_name': 'DANAJK/SIRF-Exercises', 'size': '6662'}