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!
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
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
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
Two instances of soccer players are created:
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
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
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,
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
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.
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 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
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! 🤓