Object-Oriented Programming with Python for Data Scientists

A beginner to advanced guide for Python OOP.

Object-Oriented Programming with Python for Data Scientists

Why Object-Oriented Programming (OOP)?

Before we understand what OOP is, let’s understand the backstory, and what led us to formulate “OOP”?

Why programmers thought it was essential to have such a thing? What were the pain points in the traditional way of programming?

Challenge #1: Increased Complexity

Traditional programming (or procedural programming) focuses on breaking a problem into steps or procedures executed one after the other.

While this approach was suitable for small-scale projects or experimentation, it eventually became problematic when projects transformed into large, complex systems.

In other words, it became difficult to manage, understand, and maintain the code as it grew in size and complexity.

Challenge #2: Unorganized Code

One major challenge with traditional programming was the lack of structure and organization.

Before OOP, programs were often written in a linear fashion. This made it difficult to manage large amounts of code and understand the relationships between different parts of the program.

As a result...👇

Challenge #3: Difficulty in Debugging and Testing

...traditional programming resulted in code that was arder to maintain and debug. Consequently, it was prone to more bugs and errors.

This resulted in longer development cycles and reduced software quality.

The list of challenges with traditional programming is endless.

What next?

To overcome these challenges, some computer scientists envisioned a new way of programming that would allow developers to create more flexible and adaptable software programs.

The thought process behind the new programming paradigm was inspired by real-world entities. They have certain properties and behaviors, and can interact with one another.

Thus, scientists believed that programming could be modeled in a similar fashion.

And this is how OOP was born in the late 70s.

What is Object-Oriented Programming (OOP)?

As the name suggests, Object-Oriented Programming (OOP) is a programming paradigm/technique based on the concepts of “objects.” That is why the name “object-oriented.”

This is in contrast to traditional programming where methods are executed in sequence.

The core idea of OOP is to model real-world objects and their interactions in a program.

Thus, each object is treated as a separate entity with different values for the properties.

For example, you can model a car object with properties such as color, speed, model, and methods such as start, stop, and accelerate.

How OOP solved these problems?

In response to the challenges posed by traditional programming, OOP was designed as a new programming paradigm.

Its primary aim was to improve code organization, reusability, maintainability, and scalability.

OOP introduced objects and classes (discussed below), which made it easier to organize code into manageable and reusable components.

Being organized, it was easier to understand the structure of a program, shorten the development lifecycle, and eliminate bugs and errors.

In addition to this, OOP also introduced some crucial concepts, such as inheritance. This provided a way to create relationships between classes.

Moreover, OOP allowed programmers to easily extend existing components and build complex systems. This drastically reduced the amount of code needed to be written again from scratch.

Next, let’s discuss some basic terminologies around classes and how they are defined in Python.

OOP Terminologies

OOP is defined around some core terminologies and concepts. Let’s understand them below:

1) Class

Class is a blueprint (or template) for instantiating objects. Recall the Car example discussed above. In that context, we can call Car a class.

Objects created from the same class will have the same properties and behaviors. However, the values for the properties may differ.

For instance, all car objects created from the Car class will have the same name of the properties, such as cost, color, speed, model etc. However, the values for these properties may differ, as shown below:

In Python, we define a class using the class keyword, followed by its name:

Inside a class, we define the attributes and methods that its object will have.

2) Attributes

The variables defined within a class that store information about an object are called attributes. They can also be thought of as an object’s properties.

Attributes are of two types:

2.1) Instance-level attributes

As the name suggests, these attributes are unique to each instance of a class. In other words, every time we create an object, each object gets its copy of instance-level attributes.

For example, in the Car example above, the variables cost, color, speed and model are instance-level attributes.

Also, these attributes usually have different values for each instance.

In Python, we assign the instance-level attributes in the __init__ method of a class. As the name suggests, “init” lets us initialize an object.

As __init__ is like any other Python function, we can also pass a bunch of parameters to the class method.

The first parameter in a Python class is always the self keyword. It is a special variable used as a reference to the calling object. The self keyword is followed by other parameters, as shown below:

The parameters specified in the __init__ method are assigned to the corresponding instance-level attributes.

2.2) Class-level attributes

In contrast to the instance-level attributes, which are unique to each object, these attributes are shared by all the instances of a class.

In other words, they are associated with the class itself, but not with any specific instance of the class. Therefore, they are defined outside the __init__ method.

For example, you can have a class-level attribute for the number_of_wheels of a car. This attribute would have the same value for all objects created from the car class, regardless of the color, cost, or any other instance-level attributes.

In Python, class-level attributes are defined as follows:

To access the class-level attributes, we can do the following:

3) Methods

The functions defined within the scope of a class are called methods.

They operate on the attributes of an object and are typically used to manipulate or retrieve the values stored in an object’s attributes.

An independent definition created anywhere in the program is called a “function”. However, a function is called a “method” when defined inside a class.

Like the __init__ method, class methods are also defined within the scope of the class. Also, the first parameter is always the self keyword.

For instance, let’s define a change_speed method.

This method accepts the new_speed and assigns it to the instance-level attribute speed. As shown above, we reference any instance-level attribute using the self keyword using the dot notation.

Note that a class method may or may not receive any parameters other than self. For instance, if we were to define a stop_car method, it is not necessary to pass the new speed as a parameter.

4) Object

Whenever we create an instance of a class, it is called an object.

Considering the Car class defined above, we can create a new object as follows:

The above statement invokes the __init__ method defined in the class. As a result, the arguments get assigned to the respective instance-level attributes defined in the class.

Also, the object can access the attributes and methods defined in the class. These can be accessed using the dot notation, as shown below:

When we call a class method, we don’t pass any value for the self parameter. For instance, even though the definition of change_speed() has two parameters: self and new_speed, the self parameter is automatically fetched by Python using the calling object.

Therefore, while calling the method, we only passed one value (20), which corresponds to the new_speed.

Whenever we define a new class, it creates a new datatype. For instance, if we use the type() method of Python, and pass the class object my_car, we get the following:

This indicates that the my_car object is of type Car.

Thus, in addition to making your code more organized, readable and manageable, classes also offer a mechanism to create a user-defined datatype.

Next, let’s look at some of the fundamental magic methods in Python OOP and how they are used.

Magic Methods

In Python, magic methods are methods that have double underscores at the beginning and end of their names, such as __init__, which we discussed above.

Join the Daily Dose of Data Science Today!

A daily column with insights, observations, tutorials, and best practices on data science.

Get Started!
Join the Daily Dose of Data Science Today!

Great! You’ve successfully signed up. Please check your email.

Welcome back! You've successfully signed in.

You've successfully subscribed to Daily Dose of Data Science.

Success! Check your email for magic link to sign-in.

Success! Your billing info has been updated.

Your billing was not updated.