Object Oriented Programming (OOP) with examples in Python
This post explains the concepts of object-oriented programming (OOP) and its key features, including encapsulation, abstraction, inheritance, and polymorphism. It provides examples of how these concepts can be implemented using Python, such as using private and protected variables, defining abstract classes and interfaces, creating subclasses, and implementing method overriding.
Object-oriented programming (OOP) is a programming paradigm that organizes code into objects, which are instances of classes that contain data (attributes) and behavior (methods). OOP is based on the concept of “objects,” which represent real-world entities or concepts.
In OOP, a class is a blueprint or template for creating objects. A class defines the properties and methods that an object will have, and each object created from a class will have its own set of data and behavior. OOP is a powerful and flexible programming paradigm that allows developers to create complex, modular, and scalable applications.
Many programming languages support object-oriented programming (OOP) concepts. Some of the most popular ones are:
- Java: Java is a popular OOP language that was designed to be simple, secure, and platform-independent.
- Python: Python is another popular OOP language that is known for its simplicity and ease of use.
Some key features of OOP include:
- Encapsulation: This is the process of hiding implementation details and exposing only the necessary information or functionality to the user. Encapsulation is achieved by defining public and private methods and variables within a class.
- Abstraction: This is the process of simplifying complex systems by breaking them down into smaller, more manageable parts. In OOP, abstraction is achieved by creating abstract classes or interfaces that define common functionality or behavior, which can then be implemented by other classes.
- Inheritance: This is the process of creating a new class from an existing class, inheriting its properties and methods. The new class can add or modify functionality as needed, while still maintaining the original properties and methods of the parent class.
- Polymorphism: This is the ability of objects to take on many forms or behaviors. In OOP, polymorphism is achieved through method overriding and method overloading, which allow methods to have different implementations depending on the specific object or context.
Encapsulation is the process of hiding implementation details and exposing only the necessary information or functionality to the user. In Python, encapsulation can be achieved using the following methods:
- Private variables and methods: In Python, private variables and methods can be defined by using the double underscore (
__) prefix. This makes the variable or method inaccessible outside the class. For example:
class MyClass: def __init__(self): self.__my_var = 10 def __my_method(self): print("This is a private method") my_obj = MyClass() print(my_obj.__my_var) # This will raise an AttributeError my_obj.__my_method() # This will also raise an AttributeError
- Protected variables and methods: In Python, protected variables and methods can be defined by using the single underscore (
_) prefix. This makes the variable or method accessible only within the class and its subclasses. For example:
class MyClass: def __init__(self): self._my_var = 10 def _my_method(self): print("This is a protected method") class MySubclass(MyClass): def __init__(self): super().__init__() def print_var(self): print(self._my_var) # This is accessible from the subclass my_obj = MyClass() print(my_obj._my_var) # This is accessible from outside the class, but it's not recommended my_obj._my_method() # This is accessible from outside the class, but it's not recommended my_subobj = MySubclass() my_subobj.print_var() # This will print 10
- Property methods: In Python, property methods can be used to control access to variables and provide validation or other custom behavior. Property methods can be defined using the
@propertydecorator and the setter method. The
@propertydecorator is used to define a method as a “getter” for a class attribute. When this method is called, it returns the value of the attribute. For example:
class MyClass: def __init__(self): self._my_var = 10 @property def my_var(self): return self._my_var @my_var.setter def my_var(self, value): if value > 0: self._my_var = value my_obj = MyClass() print(my_obj.my_var) # This will print 10 my_obj.my_var = 20 print(my_obj.my_var) # This will print 20 my_obj.my_var = -5 # This will not change the value of my_var because of the validation defined in the setter method print(my_obj.my_var) # This will still print 20
In Python, a property is a special kind of method that allows you to control access to an object’s attributes. Property methods are useful because they allow you to add custom logic to the act of setting or retrieving an object’s attributes, without requiring users of your object to change their code. Let us see another example:
class MyClass: def __init__(self): self._x = None @property def x(self): print("Getting x") return self._x @x.setter def x(self, value): print("Setting x") self._x = value @x.deleter def x(self): print("Deleting x") del self._x obj = MyClass() obj.x = 10 # This calls the setter method print(obj.x) # This calls the getter method # Delete the value of x del obj.x # Output: Deleting x # Try to get the value of x again print(obj.x) # Output: Getting x # Output: None
In this example,
x is a property of the
MyClass object. The
@property decorator is used to define a method called
x that serves as the getter for the
x property. This method is called whenever the
x property is accessed. In addition, a method called
x.setter is defined to set the value of the
x property. When the
x property is set, this method is called.
@property decorator can be used without the setter method, in which case the property becomes read-only. In addition, it can be used with the deleter method, which allows you to define what happens when the property is deleted. Deleter methods can be useful when you need to perform additional actions when a property is deleted, such as logging, cleaning up resources, or invalidating related properties.
In short, encapsulation in Python is achieved through the use of private and protected variables and methods, as well as property methods to control access to variables and provide validation or other custom behavior.
Abstraction is a key concept in object-oriented programming that allows complex systems to be designed and implemented in a more manageable way. Abstraction involves creating a simplified, abstract representation of a complex system that hides its implementation details and exposes only the essential features that are needed for a particular purpose.
In Python, abstraction is achieved through the use of abstract classes and interfaces. An abstract class is a class that cannot be instantiated directly, but can only be used as a superclass for other classes. An abstract class may define one or more abstract methods, which are methods that are declared but not implemented. Abstract methods serve as placeholders for methods that will be implemented in subclasses, and they provide a way to ensure that subclasses provide their own implementation of the method.
Here’s an example of how abstraction can be achieved in Python using an abstract class:
class Car: def __init__(self, make, model, year): self.make = make self.model = model self.year = year def start(self): raise NotImplementedError("Subclass must implement abstract method") def stop(self): raise NotImplementedError("Subclass must implement abstract method")
In this example, we define a
Car class that has three attributes:
year. We also define two methods,
stop, which raise a
NotImplementedError exception. These methods are considered “abstract” because they don’t have any implementation details yet.
Now, let’s create a subclass of
Car that implements the abstract methods:
class ElectricCar(Car): def __init__(self, make, model, year, battery_size): super().__init__(make, model, year) self.battery_size = battery_size def start(self): print("Starting the electric car") def stop(self): print("Stopping the electric car") my_car = ElectricCar("Tesla", "Model S", 2021, 100) my_car.start() # Output: Starting the electric car my_car.stop() # Output: Stopping the electric car
In this example, we create a subclass of
ElectricCar. We define the same three attributes as in the parent class, and we also add a
battery_size attribute. We then implement the abstract
stop methods with some implementation details specific to an electric car.
Here, we create an instance of
ElectricCar and call its
stop methods. We don’t need to know the details of how these methods are implemented, as they are abstracted away by the
Another way to perform abstraction in Python is to use the “Abstract Base Classes” module. It is a built-in module that provides a way to define abstract classes and abstract methods in Python.
from abc import ABC, abstractmethod class Shape(ABC): @abstractmethod def area(self): pass class Rectangle(Shape): def __init__(self, width, height): self.width = width self.height = height def area(self): return self.width * self.height class Circle(Shape): def __init__(self, radius): self.radius = radius def area(self): return 3.14 * self.radius * self.radius # Create instances of Rectangle and Circle rect = Rectangle(5, 6) circ = Circle(3) # Call the area() method on each instance print(rect.area()) # Output: 30 print(circ.area()) # Output: 28.26
In this example, we define an abstract class
Shape that has an abstract method
area. We then define two concrete subclasses of
Circle, that implement the area method with their own implementation details.
abc library provides a way to enforce the use of abstract classes and methods in the code. When we define an abstract method using the
@abstractmethod decorator, any concrete subclass that fails to implement that method will raise a
TypeError exception when an attempt is made to instantiate the subclass. This ensures that all concrete subclasses of an abstract class provide an implementation for the abstract method.
Inheritance is a feature of object-oriented programming that allows a new class to be based on an existing class, inheriting all its properties and methods. The existing class is known as the parent class or superclass, and the new class is known as the child class or subclass.
In Python, inheritance is achieved by creating a subclass that inherits the properties and methods of the superclass. The syntax for creating a subclass is as follows:
class Subclass(Superclass): pass
This creates a new class Subclass that inherits from the Superclass. The pass keyword is used here to indicate that the subclass has no additional properties or methods.
The subclass can then override or extend the properties and methods of the superclass, or add new ones. For example:
class Animal: def __init__(self, name): self.name = name def speak(self): print("I am an animal") class Cat(Animal): def __init__(self, name, color): super().__init__(name) self.color = color def speak(self): print("Meow") def catch_mouse(self): print("I caught a mouse!") my_animal = Animal("Leo") my_animal.speak() # This will print "I am an animal" my_cat = Cat("Whiskers", "gray") my_cat.speak() # This will print "Meow" my_cat.catch_mouse() # This will print "I caught a mouse!" print(my_cat.name) # This will print "Whiskers" print(my_cat.color) # This will print "gray"
In this example,
Cat is a subclass of
Animal, and it overrides the speak method to print “Meow” instead of “I am an animal”. It also adds a new method
catch_mouse that is specific to cats. The
__init__ method of
Cat calls the
__init__ method of
Animal using the
super() function to initialize the name property inherited from
In short, inheritance in Python allows for code reusability and makes it easier to create new classes that share properties and methods with existing ones.
Polymorphism is a feature of object-oriented programming that allows objects of different classes to be treated as if they are of the same class. This means that you can use a single interface to represent multiple classes, and you can write code that can work with objects of different classes without needing to know their specific types.
In Python, polymorphism is achieved through the use of duck typing and method overriding. Duck typing means that if an object walks like a duck and quacks like a duck, then it is treated as a duck. This means that if two objects have the same methods or attributes, they can be treated as if they are the same type of object.
Method overriding is the ability of a subclass to provide its own implementation of a method that is already defined in its parent class. When a method is called on an object of the subclass, the implementation in the subclass is used instead of the one in the parent class.
Here’s an example of how polymorphism can be achieved in Python:
class Animal: def __init__(self, name): self.name = name def speak(self): pass class Dog(Animal): def speak(self): return "Woof!" class Cat(Animal): def speak(self): return "Meow!" def animal_speak(animal): print(animal.speak()) my_dog = Dog("Fido") my_cat = Cat("Whiskers") animal_speak(my_dog) # This will print "Woof!" animal_speak(my_cat) # This will print "Meow!"
In this example,
Animal is a superclass that defines a method
speak, which does nothing.
Cat are subclasses that inherit from
Animal and override the
speak method to return “Woof!” and “Meow!”, respectively.
animal_speak function takes an object of type
Animal as an argument, and calls its
speak method. Since
Cat are both subclasses of
Animal and have overridden the
speak method, they can be passed as arguments to
animal_speak, and their
speak method will be called accordingly.
In short, polymorphism in Python allows for code that is more flexible, reusable, and easier to maintain, since it can work with objects of different types without needing to know their specific types.
Disclaimer of liability
The information provided by the Earth Inversion is made available for educational purposes only.
Whilst we endeavor to keep the information up-to-date and correct. Earth Inversion makes no representations or warranties of any kind, express or implied about the completeness, accuracy, reliability, suitability or availability with respect to the website or the information, products, services or related graphics content on the website for any purpose.
UNDER NO CIRCUMSTANCE SHALL WE HAVE ANY LIABILITY TO YOU FOR ANY LOSS OR DAMAGE OF ANY KIND INCURRED AS A RESULT OF THE USE OF THE SITE OR RELIANCE ON ANY INFORMATION PROVIDED ON THE SITE. ANY RELIANCE YOU PLACED ON SUCH MATERIAL IS THEREFORE STRICTLY AT YOUR OWN RISK.
Leave a comment