Classes: make your own types

So far your data and your functions have lived apart. A player might be a dictionary, and a separate function changes its health. That works until you have ten functions and five kinds of thing, and nobody remembers which function goes with which dictionary.

A class bundles the two together. It is a blueprint for making objects that carry their own data and their own functions:

class Player:
    def __init__(self, name, health):
        self.name = name
        self.health = health

    def take_hit(self, damage):
        self.health = self.health - damage

Reading it line by line:

  • class Player: starts the blueprint. Class names use CapitalWords.
  • __init__ (two underscores each side) runs automatically when you make a new object. Its job is to set up the starting data.
  • self is the object being worked on. self.name = name stores the name on that object, as an attribute.
  • take_hit is a method: a function that belongs to the class. Every method gets self first, so it can read and change that object's attributes.

Making objects and using them:

zoe = Player("Zoe", 100)
sam = Player("Sam", 80)
zoe.take_hit(30)
print(zoe.health)   # 70
print(sam.health)   # 80, Sam was not touched

Player("Zoe", 100) calls __init__ for you, with self filled in. You never pass self yourself; Python does it. Each object has its own copy of the attributes, which is the whole point.

The most common beginner bug here is forgetting self. inside a method. Writing health = health - damage makes a brand new local variable that vanishes when the method ends, and the object's real health never changes.

You have been using objects since lesson 1, by the way. A string is an object, and .upper() is one of its methods.

Try it yourself

Edit it. Break it. Run it again.
class Player:
    def __init__(self, name, health):
        self.name = name
        self.health = health

    def take_hit(self, damage):
        self.health = self.health - damage

    def is_alive(self):
        return self.health > 0

    def describe(self):
        return f"{self.name} has {self.health} HP"

zoe = Player("Zoe", 100)
sam = Player("Sam", 40)

zoe.take_hit(30)
sam.take_hit(50)

print(zoe.describe())
print(sam.describe())
print("Sam still in the game?", sam.is_alive())
Ctrl/Cmd + Enter runs. Esc, then Tab, leaves the editor.

Your turn

Type it yourself. That is the whole trick.

1A bank account

Finish the Account class. deposit(amount) should add to the balance and withdraw(amount) should take it away. The balance starts at whatever __init__ is given.

class Account:
    def __init__(self, owner, balance):
        self.owner = owner
        self.balance = balance

    def deposit(self, amount):
        balance = self.balance + amount

    def withdraw(self, amount):
        pass
Ctrl/Cmd + Enter runs. Esc, then Tab, leaves the editor.

2A to-do list object

Write a class TodoList. __init__ takes no extra arguments and starts an empty list in self.items. add(task) appends a task. count() returns how many tasks there are.

class TodoList:
    pass
Ctrl/Cmd + Enter runs. Esc, then Tab, leaves the editor.

Code editor. Press Control or Command plus Enter to run the code. Tab indents; to move focus out of the editor, press Escape and then Tab.