Python Object-Oriented Programming (OOP): Part 1

Learn OOP with Python, well-explained tutorial!

·

7 min read

What is OOP?

This is well explained in realpython's article on OOP.

"Object-Oriented Programming (OOP) is a method of structuring a program by bundling related properties and behaviors into individual objects."

What are objects?

Objects are like components of a system. Imagine a program as a factory assembly line of sorts. At each step of the assembly line, a system component processes some material, in the end, transforming raw material into a finished product.

Similarly, an object contains data, like the raw or preprocessed materials at each step on an assembly line, and behavior, like the action each assembly line component performs.

What will you learn?

This tutorial is hands-on, meaning you will be writing code. You'll learn how to:

  • Create a class, which can be thought of as a blueprint for creating an object
  • Use classes to create new objects
  • Create similar systems with class inheritance

What is OOP in Python?

Object-oriented programming is a programming paradigm that provides a means of structuring programs so that properties and behaviors are bundled into individual objects.

For example, an object could represent an employee at a company with properties like a name, age, address, and yearly salary. It can also represent behaviors such as walking, talking, breathing, coding, working, and running. Or, it could represent an email with properties like a recipient list, subject, body, and behaviors like adding attachments and sending.

In Python, these behaviors can be more technically known as functions. Each class can be assigned multiple functions, which we will talk more about soon.

Defining a Class in Python

Primitive data structures—like numbers, strings, and lists—are designed to represent simple pieces of information, such as the cost of a cookie, or the name of a song, or your favorite color, respectively. What if you want to represent something a little more complex?

For instance, let's say you want to track employees in your organization. You need to store some basic information about each employee, such as their name, age, position, and the year they started working.

The way you're probably thinking about right now is to use a list:

richard = ["Richard Hendricks", 34, "CEO", 2014]
james = ["James Albert", 32, "CTO", 2004]
gary = ["Gary the Snail", "CMO", 1982]

There are a number of issues with using this approach.

First, it will make larger code files more difficult to manage. If you reference richard[0] several lines away from where the richard list is declared, will you remember that the element with index 0 is the employee's name?

Second, it can throw errors if not every employee has the same number of elements in the list. In the gary list above, the age is missing, so gary[1] will return "CMO" instead of Gary the Snail's age.

A wonderful way to make this type of code more manageable, readable, and maintainable is to use classes.

Classes or Instances

Classes are used to create data structures, specifically user-defined. Classes define functions called methods, which identify the behaviors and actions that an object created from the class can perform with its data.

In this post, you'll create an Employee class that stores some information about the characteristics and behaviors that an individual employee can have.

A class is a blueprint for how something should be defined. It doesn't actually contain any formal data. The Employee class specifies that a name, age, and salary are necessary for defining an employee, but it doesn't actually contain the name, age, or salary of any employee.

While the class is the blueprint, an instance is an object that is built from a class and contains real data. An instance of the Employee class is not a blueprint anymore. It's an actual employee with a name, like Dwight Schrute, who's 43 years old.

As a reference, a class is like a form. An instance is like a form that has been filled out with information. Just like many people can fill out the same form with their own unique information, many instances can be created from a single class.

How to Define a Class

All class definitions start with the class keyword, which is followed by the name of the class and a colon. Any code that is indented below the class definition is considered part of the class's body.

Here's an example of the Employee class:

class Employee:
  pass

The body of the Employee class consists of a single statement: the pass keyword. pass is often used as a placeholder indicating where code will eventually go. It allows you to run this code without Python returning an error.

Python class names are written in a CapitalizedFormat notation by convention. For example, a class for a specific role employee like a sales representative would be written as SalesRepresentative.

The Employee class is currently empty, let's add some flavor by defining some properties that all Employee objects should have. There are a number of properties we can choose from, including name, age, salary, etc. To keep things simple, we'll just use name and salary.

The properties that all Employee objects must have are defined in a method called __init__(). Every time a new Employee object is created, .__init__() sets the initial state of the object by assigning the values of the object's properties. That is, .__init__() initializes each new instance of the class.

Note: Anything in python that contains a double underscore (__) can be called "dunder." So instead of calling it "underscore underscore init underscore underscore," you can just call it "dunder init."

You can give .__init__() any number of parameters, but the first parameter will always be a variable called self. When a new class instance is created, the instance is automatically passed to the self parameter in .__init__() so that the new attributes can be defined on the object.

Let's update the Employee class with an .__init__() method that creates .name and .salary attributes:

class Employee:
  def __init__(self, name, salary):
    self.name = name;
    self.salary = salary;

Note: From now on, I will be referencing to the .__init__() method as the initializer method.

Notice that the initializer method's signature is indented two spaces. The body is indented four spaces. Some people prefer indenting with four spaces instead of two, and eight spaces instead of four. This indentation is vitally important. It tells Python that the initializer method belongs to the Employee class.

In the body of the initializer method, there are two statements using the self variable:

  1. self.name = name creates an attribute called name and assigns it to the value of the name parameter.
  2. self.salary = salary creates an attribute called salary and assigns it to the value of the salary parameter.

Attributes created in the initializer function are called instance attributes. An instance attribute's value is specific to a particular instance of the class. All Employee objects have a name and an age, but the values for the name and age attributes will vary depending on the Employee instance.

On the other hand, class attributes are attributes that have the same value for all class instances. You can define a class attribute by assigning a value to a variable name outside of the initializer function.

For example, the following Employee class has a class attribute called position with the value of Assistant to the Regional Manager:

class Employee:
  # Class attribute
  position = "Assistant to the Regional Manager"

  def __init__(self, name, salary):
    self.name = name;
    self.salary = salary;

Class attributes are defined directly beneath the first line of the class name and are indented by two spaces (or four spaces). They must always be assigned an initial value. When an instance of the class is created, class attributes are automatically created and assigned to their initial values.

Use class attributes to define properties that should have the same value for every class instance. Use instance attributes for properties that vary from one instance to another.

Now that we have an Employee class, come back for the next post to learn about how to instantiate objects, inheritance, and more!

Conclusion

You have learned quite a lot about OOP in this article. Too bad I couldn't make it all in one part, there's just a lot to cover. I explain quite a lot in this article and I hope you understood all of it.

If you have any questions, feel free to leave them in the comments below.