Object-oriented programming (OOP) is a programming model that organizes software around objects(data) and object manipulation. OOP’s use of objects helps to break complex problems into smaller manageable parts, thus making code more straightforward to comprehend and manage, providing developers with a sense of ease. Over the next few minutes, we will go over the following core concepts as they relate to OOP:
Class
Object
Encapsulation
Inheritance
Polymorphism
Association
📓 All upcoming examples will use python code
a class is a template used to create objects. Classes define the attributes of objects and the methods that the class instances will share.
class Parent:
def __init__(self, name, hair_color):
self.name = name
self.hair_color= hair_color
def description(self):
print(f"I'm {self.name}, my hair is {self.hair_color}!")
The above snippet creates a class named Parent
, which contains attributes, name
and hair_color
and a method, description()
. Every instance of the class will have the same attributes and methods.
Regarding OOP, an object is an instance of a class. It has attributes and can perform actions defined by its class. The following example creates instances of the Parent
class; once they have been created, we can access its publicly available attributes. For example, father.hair_color
returns a value of Red
.
father= Parent("Dylan", "Red")
mother= Parent("Grace", "Brown")
father.hair_color # Red
mother.hair_color # Brown
Encapsulation bundles attributes and methods within a class and can restrict access to some of the object’s components. For example, the code below defines a Parent
class. The class has three attributes: name
, hair_color
, and __age
. The name
and hair_color
attributes are publicly accessible; however, calling the __age
attribute will result in an AttributeError. The double underscore causes an attribute to become private. To get the value of the __age
attribute, the get_age()
method must be called, as it will return the age attribute given to the Parent
.
class Parent:
def __init__(self, name, hair_color, age):
self.name = name
self.hair_color= hair_color
self.__age= age
def description(self):
print(f"I'm {self.name}, my hair is {self.hair_color}!")
def get_age(self):
return self.__age
father= Parent("Dylan", "Red", 45)
father.name # Dylan
father.__age# will result in an AttributeError
father.get_age() # 45
father.description() # I'm Dylan, my hair color is Red!
👀 ignore
super().description()
in the following example. We’ll go over this once we get to Polymorphism
Inheritance occurs when a class inherits the attributes and methods of another class. In the following example, the Child
class inherits the same attributes as the Parent
class while creating its own unrelated attributes.
class Child(Parent):
def __init__( self, name, hair_color, age, major):
super().__init__(name, hair_color, age)
self.major = major
def description(self):
super().description()
print(f"Name: {self.name}")
print(f"Hair Color: {self.get_hair_color()")
print(f"Age: {self.get_age()}")
print(f"Major: {self.major}")
child = Child("Dwight", "Auburn", 20, "Computer Science")
child.description()
#Output
# I'm Dwight, my hair color is Auburn!
# Name: Dwight
# Hair Color: Auburn
# Age: 20
# Major: "Computer Science
Polymorphism allows you to override or modify class methods in subclasses. As seen in the previous snippet on Inheritance, the Child
class adapts and modifies the Parent
method description()
. By including the super().description()
within the description()
method, you can adapt the inclusion of the Parent
output into the Child
’s description()
method output. In the next snippet, the Child
class inherits the attributes of the Parent
class but overrides the description()
method, resulting in a different output.
class Child(Parent):
def __init__(self, name, hair_color, age, major):
super().__init__(name, hair_color, age)
self.major = major
def description(self):
print(f"Hello my name is {self.name}, I'm {self.get_age()} and I major in {self.major}!")
parent = Parent("Charles", "Grey", 45)
child = Child("Dwight", "Auburn", 20, "Computer Science")
parent.description()
#Output
# I'm Charles, my hair color is Grey!
child.description()
# Hello my name is Dwight, I'm 20 and I major in Computer Science!
Association in programming is versatile, as it can be one-to-one, one-to-many, or many-to-many. It refers to the relationship between two classes where one class uses another. In the following example, we will use a one-to-many relation between classes. The Parent
class can have many children, and we can add multiple Child
instances via the add_child()
method.
class Parent:
def __init__(self, name):
self.name = name
self.children = []
def add_child(self, child):
self.children.append(child)
def list_children(self):
return [child.name for child in self.children]
def number_of_children(self):
if not self.children:
return "No children"
return len(self.children)
class Child:
def __init__(self, name, age):
self.name = name
self.age = age
parent = Parent("James")
child1 = Child("James Jr.", 12)
child2 = Child("Cameron", 16)
parent.add_child(child1)
parent.add_child(child2)
# List Children
for child in parent.list_children():
print(child)
# James Jr.
# Cameron
parent.number_of_children()
# 2
Object-oriented programming (OOP) offers a robust framework for developing modular, reusable, and maintainable code. Its foundational concepts, such as classes, objects, encapsulation, inheritance, polymorphism, and association, enable developers to create scalable and efficient software solutions. This efficiency makes OOP an indispensable paradigm in modern programming. Embracing OOP enhances code organization and facilitates easier debugging and future-proofing of applications, making developers more productive and effective.