Adventures in Machine Learning

Mastering Object-Oriented Programming in Python: Examples and Exercises

Python is a popular programming language used for a wide variety of applications, including web development, data analysis, and artificial intelligence. One of the most important concepts in Python is Object-Oriented Programming (OOP).

This article will explore OOP in Python and provide examples and exercises to help readers better understand this important topic.

OOP Concepts

At its core, OOP is about creating objects that have specific properties and methods. An object is an instance of a class, and a class defines the behavior and attributes of its objects.

In Python, we can define a class using the class keyword. Once we have created a class, we can create instances of it, which are objects with their own unique set of properties.

We can access and modify these instance variables using attributes. Attributes are variables that belong to an object, and they can be either data or methods.

Encapsulation is another key concept in OOP. It refers to the practice of keeping data and functionality within a particular class.

This ensures that the data is protected and can only be accessed and modified through defined methods.

Exercise Description

To better understand OOP, let’s walk through an exercise. We will create a class called Dog that has attributes for name, breed, and age, as well as a method that prints out the dog’s attributes.


class Dog:
def __init__(self, name, breed, age):
self.name = name
self.breed = breed
self.age = age
def describe(self):
print(f"{self.name} is a {self.breed} and is {self.age} years old.")

We can create an instance of this class and call the describe method to see the dog’s attributes:


my_dog = Dog("Fido", "Labrador Retriever", 3)
my_dog.describe() # output: Fido is a Labrador Retriever and is 3 years old.

Object Inheritance

In Python, we can create child classes that inherit properties and methods from parent classes. This allows us to create more complex programs with fewer lines of code.

Child classes have access to all the attributes and methods of their parent classes, and can also define their own attributes and methods. For example, let’s create a parent class called Vehicle that has attributes for max_speed and mileage.

We will then create a child class called Car that has an additional attribute for fuel_type and a method for honking:


class Vehicle:
def __init__(self, max_speed, mileage):
self.max_speed = max_speed
self.mileage = mileage
class Car(Vehicle):
def __init__(self, max_speed, mileage, fuel_type):
super().__init__(max_speed, mileage)
self.fuel_type = fuel_type
def honk(self):
print("Beep beep!")

We can create an instance of this child class and access its inherited attributes and methods:


my_car = Car(
120, 30000, "gasoline")
print(my_car.max_speed) # output: 120
print(my_car.mileage) # output: 30000
my_car.honk() # output: Beep beep!

Polymorphism

Another important concept in OOP is polymorphism. This refers to the ability of objects to take on different forms or be represented by multiple types.

Polymorphism allows us to write more general and flexible code. For example, let’s say we have a parent class called Shape and two child classes called Circle and Rectangle.

Each child class has a method called calculate_area that calculates the area of the shape.


class Shape:
def calculate_area(self):
pass
class Circle(Shape):
def __init__(self, radius):
self.radius = radius
def calculate_area(self):
return 3.14 * self.radius ** 2
class Rectangle(Shape):
def __init__(self, length, width):
self.length = length
self.width = width
def calculate_area(self):
return self.length * self.width

We can then create a list of shapes that includes both circles and rectangles, and call their calculate_area methods:


my_shapes = [Circle(5), Rectangle(3, 4)]
for shape in my_shapes:
print(shape.calculate_area())

This will output:


78.5
12

Property with Same Value

Sometimes we may want a class attribute to have a default value that is the same for all instances of the class. We can do this by using the property decorator.

For example, let’s say we have a class called Shape that has an attribute for color:


class Shape:
color = "white"
def __init__(self, name):
self.name = name

We could create instances of this class and access their color property:


my_shape = Shape("circle")
print(my_shape.color) # output: white

Bus Class Inheritance with Fare Calculation

Let’s explore an example of creating a child class that inherits attributes and methods from a parent class. We will create a parent class called Vehicle that has attributes for max_speed and mileage.

We will then create a child class called Bus that has an additional attribute for capacity and a method for calculating the fare for a trip.


class Vehicle:
def __init__(self, max_speed, mileage):
self.max_speed = max_speed
self.mileage = mileage
def calculate_maintenance_charge(self):
return self.max_speed * self.mileage
class Bus(Vehicle):
def __init__(self, max_speed, mileage, capacity=50):
super().__init__(max_speed, mileage)
self.capacity = capacity
def calculate_fare(self, distance):
return distance * 10 * self.capacity

We can create an instance of this child class and access its inherited attributes and methods:


my_bus = Bus(60, 10000, 30)
print(my_bus.max_speed) # output: 60
print(my_bus.mileage) # output: 10000
print(my_bus.calculate_maintenance_charge()) # output: 600000
print(my_bus.calculate_fare(10)) # output: 3000

Check Object Type

Sometimes we may need to determine the type of an object in Python. We can do this using the type function.

For example, let’s create an instance of the Circle class we defined earlier and check its type:


my_circle = Circle(5)
print(type(my_circle)) # output:

We can also use the isinstance function to check if an object is an instance of a particular class or its child classes:


print(isinstance(my_circle, Shape)) # output: True
print(isinstance(my_circle, Rectangle)) # output: False

Conclusion

In conclusion, OOP is a fundamental concept in Python that allows for the creation of objects with specific properties and methods. We can create child classes that inherit properties and methods from parent classes, allowing us to write more flexible and efficient code.

Polymorphism and encapsulation are other important concepts in OOP. By understanding these concepts and practicing exercises and examples, readers can become proficient in OOP and write more advanced Python code.

Fare Calculation for Bus Instance

In the previous section, we created a child class called Bus that inherited properties and methods from its parent class, Vehicle. In this section, we will explore how to override methods in a child class to provide different functionality.

Let’s say that we want to modify the calculate_maintenance_charge method in the Bus class to take into account the seating capacity of the bus. We can do this by overriding the method in the child class.


class Bus(Vehicle):
def __init__(self, max_speed, mileage, capacity=50):
super().__init__(max_speed, mileage)
self.capacity = capacity
def calculate_maintenance_charge(self):
return self.max_speed * self.mileage * self.capacity
def calculate_fare(self, distance):
return distance * 10 * self.capacity

We have added a new instance variable, capacity, to the bus class. In addition, we have overridden the calculate_maintenance_charge method to take into account this new variable.

Now, we can create an instance of the Bus class and call its calculate_maintenance_charge method to see the updated result:


my_bus = Bus(60, 10000, 30)
print(my_bus.calculate_maintenance_charge()) # output: 18000000

We can also call the calculate_fare method on our bus instance to calculate the fare for a trip of a certain distance:


print(my_bus.calculate_fare(10)) # output: 3000

Checking Object Type

Sometimes, we may need to check the type of an object to ensure that it is of a particular class or subclass. We can use the isinstance() method in Python to check if an object belongs to a specified class or its subclass.

In our previous example, let’s say that we have a function calculate_total_fare that takes an object of class Bus or its subclass as its parameter. We want to ensure that the object is of the correct type before performing calculations.


def calculate_total_fare(vehicle):
if isinstance(vehicle, Bus):
# Call fare calculation method on Bus instance
total_fare = vehicle.calculate_fare(10)
elif isinstance(vehicle, Vehicle):
# Call default fare calculation method on Vehicle instance
total_fare = vehicle.calculate_fare()
else:
# Raise error for invalid object type
raise TypeError("Invalid object type")
return total_fare

In the above code, we use the isinstance() method to check if the object is of type Bus or its subclass. If it is, we call the calculate_fare method on the object, using a distance of 10.

If the object is of type Vehicle instead, we use the default calculate_fare method. If the object is of any other type, we raise a TypeError.

Now, we can create a Bus object and call the calculate_total_fare function on it:


my_bus = Bus(60, 10000, 30)
print(calculate_total_fare(my_bus)) # output: 3000

We can also check if other objects are of the correct type:


my_vehicle = Vehicle(100, 20000)
print(calculate_total_fare(my_vehicle)) # output: 40000
your_car = Car(
120, 30000, "gasoline")
print(calculate_total_fare(your_car)) # raises TypeError

In summary, the isinstance() method can be used to check if an object is of a specified class or subclass. This is useful when we want to ensure that an object is of the correct type before performing certain functions on it.

In addition, we can override methods in a child class to provide different functionality than in the parent class. This allows us to create more complex and customized classes.

In this article, we explored Object-Oriented Programming (OOP) in Python and its key concepts, including creating classes and instances, attributes and methods, encapsulation, inheritance, and polymorphism. We also looked at examples and exercises to better understand OOP in Python, particularly when it comes to creating objects like classes, subclasses, and calculating fares for buses with different capacities.

Finally, we discussed the importance of checking object types using the isinstance() method, which allows us to raise errors if something is wrong with the input code. Overall, understanding OOP concepts and using them in Python can lead to more efficient and flexible code.

Popular Posts