Classes and objects
What you'll learn:
- describe your own data type with a class and create objects from it;
- explain what
selfis and why a method has one more parameter than its call; - set how an object prints and compares with
__str__,__repr__and__eq__; - tell a class attribute from an instance attribute, inherit classes and write data classes.

Picture a blueprint on the wall. It says Player and lists the fields: a name and a score. Player cards are filled in from the blueprint: the first one says Ann, the second Bob. There is one blueprint and any number of cards, and each card has its own values.
In Python, such a blueprint is called a class. But first, let's see how to manage without one. Player data can be kept in a dict, with the actions on it written as separate functions:
def add_points(player, n):
player["score"] += n
ann = {"name": "Ann", "score": 0}
add_points(ann, 5)
print(ann["name"], ann["score"]) # Ann 5The program works, but it has two weak spots:
- which keys a player has is visible only where the dict is created;
- the
add_pointsfunction accepts any dict, even one without the"score"key.
Python lets you describe a player in one place: what data it has and what can be done with it.
Class and instances
A class is a description of a new type of object, that very blueprint. An object of that type is called an instance of the class: a filled-in card. Variables tied to an instance are its attributes, the fields of the card. Functions declared inside the class are its methods, the actions on the card.
class Player:
def __init__(self, name):
self.name = name
self.score = 0
def add_points(self, n):
self.score += n
ann = Player("Ann")
ann.add_points(5)
print(ann.name, ann.score) # Ann 5Let's take apart what happens in the line ann = Player("Ann"):
- The call
Player("Ann")creates a new empty object, a blank card. - Python calls its
__init__method:selfreceives that object, andnamereceives the string"Ann". - The lines
self.name = nameandself.score = 0create the instance's attributes. - The finished object becomes the result of the call, and the name
annrefers to it.
Not every attribute comes from a parameter: every new player's score starts at 0. There is no need to return the object from __init__: the result of the call Player("Ann") is the object itself.
Class names start with a capital letter and have no underscores: Player, BankAccount. Methods are separated by one blank line.
The self parameter
Look at the call ann.add_points(5). There is one argument in the parentheses, but the method has two parameters. Python adds the other argument itself: it passes the object before the dot first, into self.
The call ann.add_points(5) means the same as Player.add_points(ann, 5). The method is stored once in the class, shared by everyone, and self tells it whose card to work with. That is why self.score += n changes the score of exactly the instance the method was called on.
Press "Next step" and watch the add_points frame. In the first call self is ann, in the second it is bob, and only that object's score changes.
1class Player:2 def __init__(self, name):3 self.name = name4 self.score = 05 6 def add_points(self, n):7 self.score += n8 9 10ann = Player("Ann")11bob = Player("Bob")12ann.add_points(5)13Player.add_points(bob, 2)14print(ann.score, bob.score)
The call Player("Ann") creates a new object and passes it to __init__.
Each call of the class creates a separate instance with its own attributes. Attributes are read and changed through a dot from outside the class too:
bob = Player("Bob")
bob.add_points(2)
print(ann.score, bob.score) # 5 2
bob.score = 10
print(ann.score, bob.score) # 5 10This is where the card analogy stops working. The method is not written on each card: it is stored once in the class, on the blueprint. Each time, it gets the card to work with through self.
Interviewers like to ask: "What is self?" The answer has three parts:
selfis a method's first parameter, and it holds the object the method was called on;- Python passes it itself:
ann.add_points(5)isPlayer.add_points(ann, 5); selfis not a keyword but a naming convention, yet it is always written.
Common mistake
The self parameter is left out of a method's declaration:
class Player:
def __init__(self, name):
self.name = name
self.score = 0
def add_points(n): # ✗
self.score += n
ann = Player("Ann")
ann.add_points(5)TypeError: Player.add_points() takes 1 positional argument but 2 were givenIn the call ann.add_points(5), Python passes two arguments, ann and 5, while the method takes one. Write self as the first parameter of every method.
Key points
- A class describes a new type of object, and each call
Player("Ann")creates a separate instance. __init__receives the new object inselfand creates its attributes.ann.add_points(5)isPlayer.add_points(ann, 5): the object before the dot goes intoself.- A method is shared by all instances, while each has its own attributes.
Subscribe to take the course
The course is free. Sign in with Telegram and subscribe to the channel to open every lesson.