class Person:
residence = "Planet Earth" # Class attribute
def __init__(self, name, age): # Constructor
self.name = name # "self" refers to the current instance of a class
self.age = age # instance attribute
self.height = 0
def introduce(self): # instance method
print(f"Hello, my name is {self.name}")
@classmethod
def wake_up(): # class method, defined with @classmethod decorator
print("Time to start your day!")
john = Person("John Casey", 38) # This invokes a call to __init__
john.age # Retrieve the age instance attribute
print(Person.residence) # class attributes are accessed without an instance
john.introduce() # instance method Called on a Person object
Person.wake_up() # Calling a class method
class Employee(Person): # Inheritance : Employee is the child class, Person is the parent class
def __init__(self, name, age, title):
super().__init__(name, age) # this is same as : "Person.__init__(self, name, age)"
self.title = title
def introduce(self): # Overriding, changing method in child class which was previously available in parent class
print(f"""My name is {self.name}, I am a {self.title}""")
def __eq__(self, other): # Overloading : Customize the behavior of Python operators for a class, applicable to magic methods
return self.name == other.name
lester = Employee("Lester", 26, "Technician")
lester.introduce() # overriden method called
# Comparison
chuck = Person("Charles Carmichael")
charles = Person("Charles Carmichael")
print(chuck == charles) # Overloading method called
# Multiple inheritance : When a child class has more than one parent
# Multilevel inheritance : In a multiple inheritance, when one of the parent is a derived class itself
# Method resolution order (MRO) : If multiple parent class has method with same name, access right is children first, then left-to-right as defined in extending the parent class names
class Student:
def __init__(self, school):
self.school = school
self.courses = []
def add_course(self, course_name):
self.courses.append(course_name)
class Intern(Employee, Student): # Multiple inheritance
def __init__(self, department, school, duration):
# Make a call to BOTH constructors
Employee.__init__(self, department)
Student.__init__(self, school)
self.duration = duration
stephen = Intern("Software Development", "Echo University", 10)
stephen.introduce() # Method from Employee
stephen.add_course("Intermediate OOP in Python") # Method from Student
print(Intern.mro()) # See MRO precedences for same name methods