Object-Oriented Python - What is self?

Do you get tripped over the self keyword when learning object oriented programming in Python? You’re not alone - it’s a common point of confusion among beginners.

In this article, I’ll try to give you a simple demonstration of the self keyword so you can see it running in the wild.

A Primer on classes and objects

Before we explore how the self argument works, Let me start with the concept of class first so that we can explain it with suitable examples. So, What is a class? A class is a blueprint for creating objects. For example, we can create an Animal class and create various animals from it.

class Animal:
    def __init__(self, arg_says, arg_eats):
        self.says = arg_says
        self.eats = arg_eats

# Creating two animal objects   
cat = Animal('Meow', 'Milk')
lion = Animal('Roar', 'Meat')
print(cat.says,'! I like ',cat.eats)
Meow ! I like  Milk
print(lion.says,'! I like ',lion.eats)
Roar ! I like  Meat

As you can see, the Animal class is a blueprint for creating any animal we want. Every animal will say something, and every animal eats something. That is because we have defined those attributes for our Animal Class.

Even though the class is the same, each object has different attribute values; the cat says meow and lion roars.

Let’s now bring self into the picture

If we try to print the cat object, we get something like this:

<__main__.Animal object at 0x11a7a76a0>

Let’s say we want to modify this object; how can we refer to it? In our class definition, we cannot use <__main__.Animal object at 0x11a7a76a0> for reference. That is because it is just the reference for the cat object. And the cat object didn’t exist at the time of defining the class. We want our class to get the reference to the correct object automatically.

This is where the self argument comes into action. When we create an object (Example: Animal('Meow', 'Milk')), the self argument is automatically passed to the __init__() method of the object. self argument is a reference to the created object. So based on the object we are working on, self (object reference) is different.

For example, when we create the cat object, the self is:
<__main__.Animal object at 0x11a7a76a0>

and when we create the lion object, the self is:
<__main__.Animal object at 0x11a7a7780>

Because we can get the correct references of objects using self argument, we can set or change the attributes of an object if we want to.

Note: self is passed automatically to the __init__() method during object creation. Therefore, you must not provide it explicitly like this when creating the object.

Animal(self, 'Meow', 'Milk')

Also, self should be present as a parameter in the __init__() method definition like this.

class Test:
    def __init__(self):
        print("Test")
# Creating an object of Test class
obj = Test()
Test

If you exclude it, you will get an error like this.

class Test:
    def __init__():
        print("Test")
# Creating an object of Test class
obj = Test()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: __init__() takes 0 positional arguments but 1 was given

As the error points out __init__() method is defined in a way that it is not expecting any arguments. But the self argument is automatically passed to the __init__() method during object creation. Therefore, self should be present in the __init__() method as a parameter.

Every object we create from a class will have a self argument to act as a reference for the object. When we create an object, the __init__() method is automatically called. Then the __init__() method uses the self argument to create and set the attribute values to that new object. That is how self.says can store Meow in the cat object and Roar in the lion object.

Now let’s check how the self argument can be used to set values after object creation.

class Animal:
    def __init__(self, arg_says, arg_eats):
        self.says = arg_says
        self.eats = arg_eats
    def set_name(self, arg_name):
        self.name = arg_name

# Creating two animal objects
# and setting it's name        
cat = Animal('Meow', 'Milk')
cat.set_name('Coco')

lion = Animal('Roar', 'Meat')
lion.set_name('Roger')
print(cat.says,'! My name is ', cat.name, '. I like ',cat.eats)
Meow ! My name is  Coco . I like  Milk
print(lion.says,'! My name is ', lion.name, '. I like ',lion.eats)
Roar ! My name is  Roger . I like  Meat

This time we created a set_name() method to give a name to our animal. We can call a method using this syntax.

object.method(arguments_if_any)

When we call the set_name() method of the object, it uses the self argument obtained during object creation to refer to the object. Then sets the name we specified as an argument to the set_name() method into the name attribute of the object.

Hope this helps :slightly_smiling_face:.

15 Likes

This was extremely helpful! I was very confused throughout the Object-Oriented Python Mission and I’ve found that this explanation along with the Animal class example make the material much easier to comprehend. Thank you so much for posting this!

2 Likes

Thank you, @Sahil! This post was very helpful. Using the animal examples made objects and self much easier to understand.

1 Like