Creating Objects and Classes

Now that we’ve used objects and know that everything in Python is an object, it’s time to define what an object is:

An object is a collection of data (variables) and methods that operate on that data

Objects and object-oriented programming are concepts that became popular in the early 1990s. Early computer languages, like C, did not have the concept of an object. However, it turned out that objects are an easy to understand paradigm for humans - it can be used to model many real-life situations. Most, if not all, new languages have the concept of objects these days. So what you’re about to learn will conceptually apply to other languages too.

Since objects are the building blocks of the Python language, it’s only logical that you can create objects yourself too. If you want to create your own type of object, you first need to define its methods and what data it can hold. This blueprint is called a class.

A class is the blueprint for one or more objects

All objects are based on a class. When we create an object, we call this ‘creating an instance of a class’. Strings, numbers, and even booleans are instances of a class too. Let’s explore with the built-in function type:

>>> type('a')
<class 'str'>
>>> type(1)
<class 'int'>
<class 'bool'>

Apparently, there are classes called strint, and bool. These are some of Python’s native classes, but we can build our own class too!

No tutorial is complete without a car analogy, so let’s make a class that represents a car. It’s a lot to type in, and you have to start over on each mistake. Feel free to try, but if you want to take a shortcut, I understand. Just copy and paste the following into your Python REPL:

class Car:
    speed = 0
    started = False

    def start(self):
        self.started = True
        print("Car started, let's ride!")

    def increase_speed(self, delta):
        if self.started:
            self.speed = self.speed + delta
            print("You need to start the car first")

    def stop(self):
        self.speed = 0

Don’t worry, we’ll go over this step by step, but let’s first create and use an object of type Car:

>>> car = Car()
>>> car.increase_speed(10)
You need to start the car first
>>> car.start()
Car started, let's ride!
>>> car.increase_speed(40)
>>> _

An object is always an instance of a class. One class can have many instances. We just created an instance of class Car, with Car(), and assigned it to the (lowercase) variable car. Creating an instance looks like calling a function ;  you’ll learn why later on.

Next, we call one of our car object methods: trying to increase its speed while it’s not started yet. Oops! Only after starting the car, we can increase its speed and enjoy the noise it makes.

Now let’s go over our Car class step by step:

  • A class is defined using the class statement, followed by the class’s name (Car). We start an indented block of code with the colon.
  • We defined two variables, speed and started. This is data that all instances of this class will have.
  • Next, we defined three methods that operate on the variables.

In the definitions of these methods, we encounter something peculiar: they all have an argument called self as their first argument.

What Is self in Python?

Honestly, this is one of Python’s less elegant language constructs if you ask me.

Remember when we were calling the methods on our car object, like car.start()? We didn’t have to pass the self variable, even though start() is defined as start(self) inside the class.

This is what’s happening:

  • When we call a method on an object, Python automatically fills in the first variable, which we call self by convention.
  • This first variable is a reference to the object itself, hence its name.
  • We can use this variable to reference other instance variables and functions of this object, like self.speed and self.start().

So only inside the class definition, we use self to reference variables that are part of the instance. To modify the started variable that’s part of our class, we use self.started and not just started. By using self, it’s made abundantly clear that we are operating on a variable that’s part of this instance and not some other variable that is defined outside of the object and happens to have the same name.

Creating Multiple Objects

Since a class is just a blueprint, you can use it to create multiple objects, just like you can build multiple identical-looking cars. They all behave similarly, but they all have their own data that is not shared between objects:

>>> car1 = Car()
>>> car2 = Car()
>>> id(car1)
>>> id(car2)

We created two car objects here, car1 and car2, and used the built-in method id() to get their ids. Each object in Python has a unique identifier, so we just proved that we created two different objects from the same class. We can use them independently:

>>> car1.start()
Car started, let's ride!
>>> car1.increase_speed(10)
>>> car1.speed
>>> car2.speed

We just started car1 and increased its speed, while car2 is still halted. Inspection of the speeds confirms these are different cars with different states!