Python Self — An Interactive Guide with Video

Many beginners who just start out with object-oriented programming in Python are confused about the purpose of the keyword “self”. Let’s resolve this confusion once and for all!

The name self is, by convention, the name of the first argument of a Python class method. The variable self points to the concrete instance on which the method is called. It is used within the method to access attributes and other methods of the same instance. The caller of the method does not explicitly pass the instance into self but leaves it to the Python interpreter to pass it automatically. For example, given an object car, Python automatically converts the method call car.drive() to drive(self=car).

Let’s have a look at a practical example.

class SoccerPlayer:


    def __init__(self, health, salary):
        
        self.health = health
        self.salary = salary

    def foul(self, player):
        
        player.health = 0
        self.salary = self.salary + 10**6


ronaldo = SoccerPlayer(100, 10**7)
beckham = SoccerPlayer(100, 10**6)

ronaldo.foul(beckham)

In the code snippet, you create a class SoccerPlayer with two methods __init__ and foul. The first arguments of the methods, named self, are references to the instance that calls it.

In the constructor method __init__, Python dynamically adds new instance attributes to the calling instance, denoted as health and salary.

Two instances of soccer players are created: ronaldo and beckham. You then call the foul() method on the ronaldo instance. When calling a method, you do not need to explicitly define the self argument — Python does it for you. It takes the reference to the ronaldo instance and passes it as the first argument, called self, into the foul() method.

A foul has a negative impact on the health of the victim. So as Ronaldo fouls Beckham, Beckham’s health declines and is set to zero. At the same time, the salary of Ronaldo goes up by 1,000,000 units—don’t ask me why.

Let’s have a look at a puzzle that checks your understanding so far. Can you solve it?

# PUZZLE:
print(beckham.health)
print(ronaldo.health)

print(beckham.salary)
print(ronaldo.salary)
# What's the output of all four lines?

Exercise: What’s the output of this code snippet?

You can check if your guess is correct in the following interactive code shell. Just hit “Run” and see the result!

Explanation: The challenge of this puzzle is to differentiate the instance references self and player within the foul() method.

So the result is the following:

  • beckham.health reduces to 0
  • ronaldo.health stays 100
  • beckham.salary stays 1,000,000
  • ronaldo.salary increases to 11,000,000

Now, let’s make this a bit harder, shall we?

class SoccerPlayer:


    def __init__(self, health, salary):
        
        self.health = health
        self.salary = salary

    def foul(self, player):
        
        player.health = 0
        self.salary = self.salary + 10**6


ronaldo = SoccerPlayer(100, 10**7)
beckham = SoccerPlayer(100, 10**6)

SoccerPlayer.foul(beckham, ronaldo)

print(beckham.health)
print(ronaldo.health)

print(beckham.salary)
print(ronaldo.salary)

The puzzle seems similar to the above one but with an important difference: You call the foul() method on the class rather than any particular instance. This has the benefit that we can explicitly define ALL arguments, including the self argument. In this way, we can dynamically decide which instance fouls which other instance. In this puzzle, beckham fouls ronaldo. So Beckham get’s the salary bump and Ronaldo the health issues:

  • beckham.health stays 100
  • ronaldo.health reduces to 0
  • beckham.salary doubles to 2,000,000
  • ronaldo.salary stays at humble 10,000,000

Conclusion

In summary, the self argument is similar to “this” in Java, or “@” in some other languages. Semantically, it refers to the instance on which the method modifies the data. Still, Python does not prevent a method to modify other instance’s data as well.

However, the self argument is not a reserved keyword in Python. You can call it anything you want. Nevertheless, you shouldn’t do this as mentioned above. This clearly violates the expectations of all other Python coders out there.

There have been a few voices that requested that the self argument should be a reserved keyword in future Python versions. But the creator of Python Guido van Rossum has explicitly defended the current use of self in his article. Although the article is written many years ago, the main arguments for (and against) the self argument still hold.

Here are two of his arguments from the article why self should remain as is:

“There’s a pretty good argument to make that requiring explicit ‘self’ in the parameter list reinforces the theoretical equivalency between these two ways of calling a method, given that ‘foo’ is an instance of ‘C’:

foo.meth(arg) == C.meth(foo, arg)

Another argument for keeping explicit ‘self’ in the parameter list is the ability to dynamically modify a class by poking a function into it, which creates a corresponding method. For example, we could create a class that is completely equivalent to ‘C’ above as follows:

# Define an empty class:
class C:
   pass

# Define a global function:
def meth(myself, arg):
   myself.val = arg
   return myself.val

# Poke the method into the class:
C.meth = meth


There is a reason why Guido kept his place at the top for that many years!

I just want to note that the second argument is also what we have discussed above: Call the method on the class and define the self argument explicitly rather than letting it Python do for us.

Where to Go From Here?

Forget what they tell you. You must know the Python basics by heart. If you cannot even write a small code snippet without googling keywords, the PEP standard, or basic functionality, you seriously harm your coding productivity.

To teach you the basics, I have created 5 FREE cheat sheets that teach you everything you need to know to get started. Fill in your email, download the cheat sheets, print them, and post them to your toilet wall! 🤓

Leave a Comment

Your email address will not be published. Required fields are marked *