Table of contents
No headings in the article.
What is OOP?
Object-oriented programming is a programming style that constructs software architecture around data or objects rather than functions and logic. An object is a data field with particular characteristics and behaviours. OOP (as programmers popularly abbreviate it) is a programming style aligned or built around objects.
It is crucial to master OOP for each programming language being used because the principles of OOP are handled slightly differently in each language. In this article, Python will be used to explain the concepts of OOP. Other well-known object-oriented programming languages include Objective C, Perl, Python, Javascript, Simula, Modula, Ada and Java.
As earlier stated, object-oriented programming is centred on constructing reusable "objects" with unique features and behaviours that can be interacted with, modified, and packaged. Large, sophisticated, and actively updated or maintained programs fit this development method well.
Classes, Objects, Polymorphism, Abstraction, Encapsulation, and Inheritance are the foundations of OOP.
Classes
Classes are custom datatypes developers create that serve as a blueprint for an object. They consist of data members and member functions, which can only be used by creating an instance of that class. It is the collection of attributes or operations shared by all objects of a particular type. By convention class names adopt the Pascal case naming convention.
Syntax
class ClassName:
'Optional class documentation string'
# functions, methods and other implementations go in here
Example
class Person:
'This is a base class for a person'
height = 0
def __init__(self, name, age=18):
self.name = name
self.age = age
Person.height = 170
Objects
An object is an instance of a class; usually, no memory is allocated when a class is created, but memory is allocated when an object is initialized. An object's identity, state, and behaviour are all defined. Each object contains all the data and code needed to manipulate the object.
class Person:
'This is a base class for a person'
height = 0
def __init__(self, name, age=18):
self.name = name
self.age = age
Person.height = 170
# This line of code will create the person1 object from the 'Person' class and set the name to Harry and age to 33*
person1 = Person("Harry", 33)
# This line of code will create the person2 object from the 'Person' class and set the name to Meghan and age to 18 (since no age was specified when the object was created, the default age set by the developer will be used)
person2 = Person("Meghan")
Polymorphism
Polymorphism can be defined as different forms of a method or function. It is helpful when creating other classes that have methods with the same name. Polymorphism makes reusing code easy and also less complex.
Polymorphism can occur in
- Operators
The + operator can take two inputs and return a result depending on the inputs. In the examples below,
The integer inputs produced an integer output
The output changed to float because one of the inputs is a float
Lastly, strings were concatenated when operated upon
Example
diameter = 6
height = 12
pi = 3.142
print(height + diameter) # 18
print(type(height + diameter)) # <class 'int'>
print(height + pi) # 15.142
print(type(height + pi)) # <class 'float'>
string1 = "Star"
string2 = "Gazing"
print(string1 + string2) # StarGazing
print(type(string1 + string2)) # <class 'str'>
All this occurs automatically as a result of the way Python's + operator was designed.
- Built-in functions
We can also see that certain built-in Python functions can accept inputs of various types and then handle them in various ways. Every letter is counted when a string value is passed to len(). However, it behaves differently if a tuple, list or dictionary is provided as input.
Example
string1 = 'Python is amazing!'
tuple1 = ('Spring','Summer','Autumn','Winter')
list1 = ['Africa','Europe','Asia']
dictionary1 = {'Eyes':'Blue','Hair':'Blonde','Piercings':'None', 'Rings': 2}
print(len(string1)) # 18
print(len(tuple1)) # 4
print(len(list1)) # 3
print(len(dictionary1)) # 4
- User-defined functions
Methods with the same name but wrapped in distinct class names can be created. Therefore, we can repeat running the same method with a different class name prefixed to get different results. Two classes, a window class and a door class, are created and initialized in the example below, with both open and closed methods.
class Window:
def __init__(self, angle):
self.angle = angle
def open(self):
return print(f"Window opened {self.angle} degrees")
def close(self):
return print(f"Window closed {self.angle} degrees")
Encapsulation
Encapsulation is a technique for limiting access to specific areas of an object or class to avoid unintentionally changing data or behaviour. Python uses private and protected instance variables and methods to implement encapsulation. A double underscore is used to indicate private variables and methods, while a single underscore is used to indicate protected variables and methods. Using encapsulation ensures that the internal implementation details of the source code are hidden from the outside world.
The public Access Modifier
The public member can be accessed from either inside or outside the class.
The protected Access Modifier
Only the class and its subclasses provide access to the protected member. An underscore before the member name indicates that the name is protected.
The private Access Modifier
The private member is accessible only inside the class. Adding two underscores before the member name indicates the member is private.
class Employee:
def __init__(self, name, department, salary):
# public member
self.name = name
# protected member
self._department = department
# private member
self.__salary = salary
# Initializing an object with the employee class
employee = Employee('James Bond', 'MI5', 10000)
# Attempting to access private data members fails
print('Salary:', employee.__salary) # AttributeError: 'Employee' object has no attribute '__salary'
# This can be fixed by changing to last line to:
print('Salary:', employee._Employee__salary)
Getters and Setters
Python requires the usage of setters and getters in order to provide good encapsulation. Data encapsulation is the primary goal of using getters and setters in object-oriented applications. To access and edit data members, use the getter and setter methods, respectively.
class Employee:
def __init__(self, name, id):
# public member
self.name = name
# private member
self.__id = id
def show(self):
print(f'Employee name: {self.name}, \n Employee ID: {self.__id}')
# getter methods
def get_id(self):
return self.__id
# setter method to modify data member
def set_id(self, emp_id):
# conditional state to allow/prevent data modification
if emp_id == self.__id:
print('Error, new ID is the same as the old ID')
else:
self.__id = emp_id
emp_mark = Employee('Mark', 1075878)
# Before modification
emp_mark.show()
# Changing the ID using setter
emp_mark.set_id(1075373)
# After modification
emp_mark.show()
Abstraction
Abstraction is the practice of shielding the user from the implementation specifics of a class or method. Because of this, the user may concentrate on what the class or function performs instead of worrying about how it is implemented.
Inheritance
Like in real life, inheritance implies creating a new class by deriving from a pre-existing class. The pre-existing class is called the parent class, and the derived class is called the child class. The child class inherits the attributes of the parent class and can be used as if they were defined in the child class. The child class also can override methods from its parent class.
class ChildClass (ParentClass):
'Optional class documentation string'
# class methods, functions and other implementations go in here
class Microsoft:
def __init__(self):
return print ("Welcome to Microsoft")
def location(self):
return print ("Worldwide")
def industry(self):
return print ("Technology")
class ADC(Microsoft):
def __init__(self):
return print ("Welcome to Microsoft Africa Development Centre")
# The location method in the child class overwrites the location method in the parent class
def location(self):
return print ("Lagos, Nigeria")
# The industry methods is not defined in the child class so it will be inherited from the parent class
parent_company = Microsoft() # Welcome to Microsoft
parent_company.location() # Worldwide
parent_company.industry() # Technology
child_company = ADC() # Welcome to Microsoft Africa Development Centre
child_company.location() # Lagos, Nigeria
child_company.industry() # Technology
Advantages of object-oriented programming
Object-oriented programming is considered more productive than conventional procedure-based programming techniques in terms of software development due to some of the following reasons:
Modularity: Object-oriented programming is modular because it creates a clear division of labour in the creation of object-based programs.
Extensibility: It is also extendable, as new characteristics and actions may be added to objects.
Reusability: Objects can be reused within and between apps. This effectively increases productivity as less time can be spent writing code.
Faster development is made possible via reuse. Rich object libraries are provided with object-oriented programming languages, and project-specific code can be reused in other projects.
High-quality software: Software of higher quality is produced more quickly and at a lesser cost, which frees up more time and resources for the software's verification.
Disadvantages of object-oriented programming
Steep learning curve: Some fundamental programming concepts, like inheritance and polymorphism, can be initially difficult to grasp. It may take some time for some people to get used to how object-oriented programming requires them to think.
Increased program size: Procedural applications often have fewer lines of code than object-oriented programs.
Longer runtime: Object-oriented programs are typically slower than procedure-based programs because they often need to execute more instructions.
Not appropriate for every issue: Using object-oriented programming to solve some problems will not produce efficient programs because some problems are better suited to functional programming, logic programming, or procedure-based programming.
Conclusion
Designing software with OOP concepts can be a task. If there is a clearly outlined plan for a program, OOP can be used to create it. The size of OOP-developed programs is larger than that of procedural-developed applications but is much easier to maintain. OOP is recommended paradigm for most projects as the advantages seemingly outweigh the disadvantages, but when planning a project, it is recommended to explore all available options.