Python Part 8: Object-Oriented Programming In Python (Classes and Objects)

Python Part 8: Object-Oriented Programming In Python (Classes and Objects)


Please Subscribe Youtube| Like Facebook | Follow Twitter

Object-Oriented Programming In Python

In this article, we will provide a detailed overview of Object-Oriented Programming In Python (Classes and Objects) and provide examples of how they are used in Python programming.

Python’s Object-Oriented Programming (OOP) is an incredible paradigm built upon four key pillars. These pillars, encapsulation, inheritance, polymorphism, and abstraction, provide a solid foundation for creating efficient and flexible code structures. In this article, we will explore the unique essence of each pillar and understand how they contribute to the power of Python’s OOP.

The Pillars of Object-Oriented Programming

OOP is built upon four key pillars: encapsulation, inheritance, polymorphism, and abstraction.

Encapsulation

Encapsulation in Python ensures data and behavior are bundled within classes, allowing controlled access and enhanced security. With access modifiers like public, private, and protected, Python enables developers to organize code effectively and protect sensitive information. This pillar strengthens data integrity and promotes modular code organization.

Inheritance

Python’s inheritance facilitates the creation of new classes by inheriting attributes and behaviors from existing ones. This pillar promotes code reuse, reduces redundancy, and fosters code evolution. With support for single and multiple inheritance, Python empowers developers to construct complex class hierarchies, establishing logical relationships between classes effortlessly.

Polymorphism

Polymorphism allows objects in Python to exhibit multiple forms and behaviors. Through dynamic typing, Python enables different classes to implement methods with the same name but with unique implementations. This feature enhances code flexibility, readability, and adaptability. Polymorphism empowers developers to write concise and modular code that accommodates diverse object types.

Abstraction

In Python, abstract classes and interfaces are not built-in language features like in some other programming languages such as Java or C#. However, Python provides a mechanism to define abstract classes using the abc (Abstract Base Classes) module, which can be used to achieve similar functionality.

We will explain them further in detail in next article. In this article we will explain Classes and Objects

Classes and Objects

In Python, a class is a blueprint for creating objects that share similar characteristics and behaviors. It defines a structure or template that describes the data attributes (variables) and methods (functions) associated with the objects. Objects, on the other hand, are instances of classes. They represent specific entities or things that can be manipulated and interacted with in your program.

Defining a Class

To define a class in Python, you use the class keyword followed by the class name. Let’s consider an example of a class called Car:

class Car:
    def __init__(self, make, model, year):
        self.make = make
        self.model = model
        self.year = year

    def start_engine(self):
        print("Engine started!")

In the above code snippet, we define a class named Car that has three data attributes: make, model, and year. The init method is a special method called a constructor, which is executed automatically when an object is created from the class. It initializes the attributes of the object with the provided values. Additionally, we have defined a method named start_engine that simply prints a message indicating that the engine has started.

Creating Objects

Once we have defined a class, we can create objects (instances) of that class using the class name followed by parentheses. Let’s create a couple of Car objects:

car1 = Car("Toyota", "Corolla", 2022)
car2 = Car("Honda", "Civic", 2023)

In the above code, we create two instances of the Car class, namely car1 and car2. We pass the respective make, model, and year values as arguments to the class’s constructor (init method). Each object will have its own set of attributes, independent of other objects.

Fields (Instance Variables) in Python

Fields, also known as instance variables, store the state or data associated with objects. They hold unique values for each instance of a class. Fields are defined within a class and can be accessed and modified using the dot notation. Here’s an example:

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age
    
    def introduce(self):
        print(f"My name is {self.name} and I am {self.age} years old.")

In the above code snippet, we define a class called Person with two fields: name and age. The constructor __init__ method initializes these fields with the provided values. We also define an introduce method that prints a message introducing the person.

To access and modify the fields of an object, we use the dot notation:

person = Person("John", 25)
person.name = "Adam"
person.introduce()  # Output: My name is Adam and I am 25 years old.

In the code above, we create an instance of the Person class called person with the name “John” and age 25. We then modify the name field to “Adam” and call the introduce method, which prints the updated introduction.

Methods in Python

Methods are defined within a class and are responsible for performing specific actions or tasks. They encapsulate behavior that objects of the class can exhibit. To define a method in Python, you use the def keyword followed by the method name and parentheses, optionally containing parameters. Here’s an example:

class Circle:
    def __init__(self, radius):
        self.radius = radius
    
    def calculate_area(self):
        return 3.14 * self.radius * self.radius

In the above code snippet, we define a class called Circle with two methods. The init method is a constructor, which we’ll discuss in more detail later. The calculate_area method calculates and returns the area of the circle using the radius attribute.

To access a method of an object, you use the dot notation, similar to accessing attributes:

circle = Circle(5)
area = circle.calculate_area()
print(area)  # Output: 78.5

In the code above, we create an instance of the Circle class called circle with a radius of 5. We then call the calculate_area method of the circle object and store the result in the area variable. Finally, we print the calculated area, which is 78.5 in this case.

Constructors in Python

Constructors are special methods used to initialize objects. They have the same name as the class and are responsible for setting initial values to the object’s fields. In Python, constructors can take parameters, allowing you to pass values during object creation. Constructors can be categorized into two main types: no-argument constructors and parameterized constructors.

No-Argument/Non-Parameterized Constructors

A no-argument constructor does not take any parameters and initializes the parameters, providing default values for the object’s fields. Here’s an example:

class Rectangle:
    def __init__(self):
        self.width = 0
        self.height = 0

In the above code snippet, we define a class called Rectangle with a no-argument constructor. The constructor initializes the width and height fields to 0.

Parameterized Constructors

A parameterized constructor, on the other hand, takes parameters that allow you to set specific initial values for the object’s fields. Here’s an example:

class Square:
    def __init__(self, side_length):
        self.side_length = side_length

In the code above, we define a class called Square with a parameterized constructor. The constructor takes a side_length parameter and assigns it to the side_length field.

To create objects using constructors, you simply call the class name followed by parentheses, passing the necessary arguments if required:

rectangle = Rectangle()
square = Square(5)

In the code snippet above, we create an instance of the Rectangle class called rectangle using the no-argument constructor. We also create an instance of the Square class called square using the parameterized constructor, passing the side length as 5.

self keyword

In Python, the ‘self’ keyword holds significant importance within the context of classes and objects. It is used as a convention to refer to the instance of a class within its own methods. The ‘self’ keyword allows you to access and manipulate the attributes and methods of an object.

When defining methods within a class, the first parameter is conventionally named ‘self’. This parameter represents the instance of the class itself. By using ‘self’, you can access the attributes and call the methods associated with that specific instance. Let’s consider an example:

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def introduce(self):
        print(f"My name is {self.name} and I am {self.age} years old.")

In the code snippet above, we define a class named ‘Person’ with an ‘init‘ method and an ‘introduce’ method. The ‘init‘ method is a constructor that initializes the ‘name’ and ‘age’ attributes of the object. The ‘introduce’ method uses ‘self’ to access the ‘name’ and ‘age’ attributes and prints a formatted introduction.

To create an instance of a class and call its methods, we use the dot notation, along with the ‘self’ parameter implicitly passed. Here’s an example:

person = Person("John", 25)
person.introduce()  # Output: My name is John and I am 25 years old.

In the code snippet above, we create an instance of the ‘Person’ class named ‘person’ with the name “John” and age 25. We then call the ‘introduce’ method of the ‘person’ object, which accesses the ‘name’ and ‘age’ attributes using ‘self’ and prints the formatted introduction.

Example Code

Here’s an example code snippet demonstrating the usage of classes, objects, and the ‘self’ keyword in Python, along with the corresponding output:

class Rectangle:
    def __init__(self, length, width):
        self.length = length
        self.width = width

    def calculate_area(self):
        return self.length * self.width

    def calculate_perimeter(self):
        return 2 * (self.length + self.width)


# Creating instances of the Rectangle class
rectangle1 = Rectangle(4, 6)
rectangle2 = Rectangle(3, 5)

# Accessing attributes and calling methods
area1 = rectangle1.calculate_area()
perimeter1 = rectangle1.calculate_perimeter()
print("Rectangle 1:")
print("Area:", area1)  # Output: Area: 24
print("Perimeter:", perimeter1)  # Output: Perimeter: 20

area2 = rectangle2.calculate_area()
perimeter2 = rectangle2.calculate_perimeter()
print("\nRectangle 2:")
print("Area:", area2)  # Output: Area: 15
print("Perimeter:", perimeter2)  # Output: Perimeter: 16

Output

Rectangle 1:
Area: 24
Perimeter: 20

Rectangle 2:
Area: 15
Perimeter: 16

In the above code, we define a class called ‘Rectangle’ with attributes ‘length’ and ‘width’, as well as methods ‘calculate_area’ and ‘calculate_perimeter’. We then create two instances of the ‘Rectangle’ class, ‘rectangle1’ and ‘rectangle2’, with different length and width values.

We calculate and display the area and perimeter of ‘rectangle1’ and ‘rectangle2’ using the ‘calculate_area’ and ‘calculate_perimeter’ methods. The output shows the respective area and perimeter values for each rectangle.

Static Method And Non-Static Method In Python

Static Method

Static methods are methods that belong to the class itself, rather than an instance of the class. They do not operate on instance-specific data and do not require an instance of the class to be called.

Characteristics:

  1. Declared using the @staticmethod decorator.
  2. Can be called directly from the class itself without the need for an instance.
  3. Cannot access or modify instance attributes or methods.
  4. Typically used for utility functions or operations that are not tied to any specific instance.

Example:

class MathUtils:
    @staticmethod
    def add_numbers(a, b):
        return a + b

result = MathUtils.add_numbers(5, 3)
print(result)  # Output: 8

In the example above, we define a static method called ‘add_numbers’ within the ‘MathUtils’ class. This method takes two parameters, ‘a’ and ‘b’, and returns their sum. The static method is called directly from the class itself without creating an instance of the class.

Non-Static Methods (Instance Methods):

Non-static methods, also known as instance methods, are methods that require an instance of the class to be called. They operate on instance-specific data and can access instance attributes and other methods.

Characteristics:

  1. Defined without the @staticmethod decorator.
  2. Can only be called on instances of the class.
  3. Have access to instance attributes and methods using the ‘self’ keyword.
  4. Typically used to perform actions specific to individual instances of the class.

Example:

class Circle:
    def __init__(self, radius):
        self.radius = radius

    def calculate_area(self):
        return 3.14 * self.radius * self.radius

circle = Circle(5)
area = circle.calculate_area()
print(area)  # Output: 78.5

In the example above, we define a class called ‘Circle’ with an instance method called ‘calculate_area’. This method uses the ‘self’ keyword to access the ‘radius’ attribute of the specific instance and calculates the area of the circle.

Differences between static and non-static methods In Python

TermStatic MethodNon-Static Method (Instance Method)
DeclarationDecorated with @staticmethodDefined without decorator
Calling SyntaxClassName.methodName()instance.methodName()
Access toNo access to instance attributes or methodsHas access to instance attributes and methods
Instance Specific DataNoYes
PurposeUtility functions, general operationsActions specific to individual instances of class

Conclusion

In conclusion, classes and objects are the fundamental building blocks of object-oriented programming (OOP). They enable us to organize and structure our code in a way that closely mirrors real-world entities and their interactions. By encapsulating data and behavior within classes, we can create objects that represent specific instances of those classes.

Classes act as blueprints or templates, defining the attributes (data) and methods (behavior) that objects of that class will possess. Objects, on the other hand, are instances of classes that have their own state and behavior.

Python Beginner Tutorial Series

Please Subscribe Youtube| Like Facebook | Follow Twitter


Leave a Reply

Your email address will not be published. Required fields are marked *