<jupyter_start><jupyter_text>Polymorphism - ability to take multiple formsOne in many forms is nothing but polymorphism<jupyter_code>class Vehicle:
    
    def __init__(self, color, maxSpeed):
        self.color = color
        self.__maxSpeed = maxSpeed    #Making maxSpeed as private using '__' before the memeber
    
    def getMaxSpeed(self):            #get method is a public function
        return self.__maxSpeed
    
    def setMaxSpeed(self, maxSpeed):  #set method is a public function
        self.__maxSpeed = maxSpeed
        
    def print(self):                            #Another way of accessing printing private members --> printing within a class
        print("Color : ",self.color)
        print("MaxSpeed :", self.__maxSpeed)

class Car(Vehicle):
    
    def __init__(self, color, maxSpeed, numGears, isConvertible):
        
        super().__init__(color, maxSpeed) #Inheriting from vehicle class       
        self.numGears = numGears          #Passing via arguments in car class
        self.isConvertible = isConvertible 
        
    def print(self): 
        #self.print()                 #Here there is only one print() and we can use self or super in this example.
        print("NumGears :", self.numGears)
        print("IsConvertible :", self.isConvertible)
        
c = Car("red", 35, 5, False)
c.print()<jupyter_output>NumGears : 5
IsConvertible : False<jupyter_text>** Here the vehicle and car class has the same method name with same arguments (so called) ---> Method Overloading (in programming)So, c.print() first searches in the car class if print() is present then it prints else it goes to its parent class (Vehicle class in the below example). As we removed the print() from class Car then the control goes to the print() of Vehicle class (parent class).      Suppose if the print() is not available in the parent class then the control goes to its parent class and so on till it reaches the print()<jupyter_code>class Vehicle:
    
    def __init__(self, color, maxSpeed):
        self.color = color
        self.__maxSpeed = maxSpeed    #Making maxSpeed as private using '__' before the memeber
    
    def getMaxSpeed(self):            #get method is a public function
        return self.__maxSpeed
    
    def setMaxSpeed(self, maxSpeed):  #set method is a public function
        self.__maxSpeed = maxSpeed
        
    def print(self):                            #Another way of accessing printing private members --> printing within a class
        print("Color : ",self.color)
        print("MaxSpeed :", self.__maxSpeed)

class Car(Vehicle):
    
    def __init__(self, color, maxSpeed, numGears, isConvertible):
        
        super().__init__(color, maxSpeed) #Inheriting from vehicle class       
        self.numGears = numGears          #Passing via arguments in car class
        self.isConvertible = isConvertible 
        
#     def printCar(self):
#         #super().print()             #Instead of super() you can also use self.print() beause a car inherits all properties and methods from parent class
#         self.print()                 #Here there is only one print() and we can use self or super in this example.
#         print("NumGears :", self.numGears)
#         print("IsConvertible :", self.isConvertible)
        
c = Car("red", 35, 5, False)
c.print()
class Vehicle:
    
    def __init__(self, color, maxSpeed):
        self.color = color
        self.__maxSpeed = maxSpeed    #Making maxSpeed as private using '__' before the memeber
    
    def getMaxSpeed(self):            #get method is a public function
        return self.__maxSpeed
    
    def setMaxSpeed(self, maxSpeed):  #set method is a public function
        self.__maxSpeed = maxSpeed
        
#     def print(self):                            #Another way of accessing printing private members --> printing within a class
#         print("Color : ",self.color)
#         print("MaxSpeed :", self.__maxSpeed)

class Car(Vehicle):
    
    def __init__(self, color, maxSpeed, numGears, isConvertible):
        
        super().__init__(color, maxSpeed) #Inheriting from vehicle class       
        self.numGears = numGears          #Passing via arguments in car class
        self.isConvertible = isConvertible 
        
#     def printCar(self):
#         #super().print()             #Instead of super() you can also use self.print() beause a car inherits all properties and methods from parent class
#         self.print()                 #Here there is only one print() and we can use self or super in this example.
#         print("NumGears :", self.numGears)
#         print("IsConvertible :", self.isConvertible)
        
c = Car("red", 35, 5, False)
c.print()<jupyter_output><empty_output><jupyter_text>In the above example, there is no print in the entire program so ERROR<jupyter_code>class Vehicle:
    
    def __init__(self, color, maxSpeed):
        self.color = color
        self.__maxSpeed = maxSpeed    #Making maxSpeed as private using '__' before the memeber
    
    def getMaxSpeed(self):            #get method is a public function
        return self.__maxSpeed
    
    def setMaxSpeed(self, maxSpeed):  #set method is a public function
        self.__maxSpeed = maxSpeed
        
    def print(self):                            #Another way of accessing printing private members --> printing within a class
        print("Color : ",self.color)
        print("MaxSpeed :", self.__maxSpeed)

class Car(Vehicle):
    
    def __init__(self, color, maxSpeed, numGears, isConvertible):
        
        super().__init__(color, maxSpeed) #Inheriting from vehicle class       
        self.numGears = numGears          #Passing via arguments in car class
        self.isConvertible = isConvertible 
        
    def print(self): 
        super().print()                 #Here there is only one print() and we can use self or super in this example.
        print("NumGears :", self.numGears)
        print("IsConvertible :", self.isConvertible)
        
c = Car("red", 35, 5, False)
c.print()

print("_____________________________")

v = Vehicle("green", 98)
v.print()
#Predict the Output:
class Vehicle:
    def __init__(self,color):
        self.color = color
    def print(self):
        print(c.color,end=" ")
class Car(Vehicle):
    def __init__(self,color,numGears):
        super().__init__(color)
        self.numGears = numGears
    def print(self):
       print(c.color,end=" ")
    print(c.numGears)
c = Car("black",5)
c.print()
#Predict the Output:
class Vehicle:
    def __init__(self,color):
        self.color = color
    def print(self):
        print(c.color,end=" ")
class Car(Vehicle):
    def __init__(self,color,numGears):
        super().__init__(color)
        self.numGears = numGears
    def print(self):
        self.print()
        print(c.numGears)
c = Car("black",5)
c.print()<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.09127730363084044, 'fraction_numerical': 0.0024591349631129756, 'mean_word_length': 2.4604604604604603, 'pattern_counts': {'":': 0, '<': 12, '<?xml version=': 0, '>': 17, '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': '3', 'dir': 'jupyter-structured-clean-dedup', 'id': '392797', 'license': 'Unlicense', 'n_tokens_mistral': 1951, 'n_tokens_neox': 1909, 'n_words': 653, 'path': '04 OOPS-2/4.4 Polymorphism (Method overriding).ipynb', 'repo_name': 'suhassuhas/Coding-Ninjas---Data-Structures-and-Algorithms-in-Python', 'size': '6913'}