Classes and objects

Intermediate

Introduction

A class describes a new kind of value: what data it holds and what it can do. An object is one value made from that class. Classes are how large programs keep related data and behaviour together.

Once a program has many related values, loose variables and separate functions become hard to keep in step. A class keeps an account's balance and the rules for changing it together, so that no other code can forget those rules.

How it works

Defining a class

class Student:
    def __init__(self, name, cgpa):
        self.name = name
        self.cgpa = cgpa

    def is_good(self):
        return self.cgpa >= 3.5

s1 = Student("Rahim", 3.75)
s2 = Student("Nadia", 3.2)
print(s1.name, s1.is_good())
print(s2.name, s2.is_good())
Open in compiler

Step through slowly and watch the objects panel:

  1. Python runs the class body once, collecting the methods __init__ and is_good.
  2. Student("Rahim", 3.75) creates a new, empty object and calls __init__ with it as self. The frame shows self pointing to the new object.
  3. self.name = name stores an attribute on that object; the object's box gains a name field, then a cgpa field.
  4. The same happens again for s2: a second, separate object with its own attributes.

s1.is_good() calls a method: Python passes s1 as self, so the method can read self.cgpa.

Two names, one object

class Counter:
    def __init__(self):
        self.value = 0

a = Counter()
b = a
b.value = 5
print(a.value)
Open in compiler

Objects behave like lists: b = a does not copy the object. Both names point to the same box, so setting b.value = 5 changes what a.value shows too.

Syntax

class Dog:
    def __init__(self, name):
        self.name = name

    def speak(self):
        return f"{self.name} says woof"

rex = Dog("Rex")
rex.speak()

Example

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

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

    def withdraw(self, amount):
        if amount > self.balance:
            print("Not enough money")
        else:
            self.balance = self.balance - amount

acc = Account("Karim")
acc.deposit(500)
acc.withdraw(800)
acc.withdraw(200)
print(acc.balance)
Open in compiler

deposit and withdraw change self.balance. Watch the object's balance field: 0, then 500. The 800 withdrawal is refused, then it ends at 300. Keeping the rule "no withdrawing more than you have" inside the class means no other code can break it by accident.

Line by line

  1. class Account: runs once and collects the methods.
  2. Account("Karim") makes an object and calls __init__, which sets owner and balance.
  3. acc.deposit(500) passes acc as self, so the balance becomes 500.
  4. acc.withdraw(800) is refused, because the rule is inside the method.
  5. acc.withdraw(200) succeeds, and the final balance of 300 is printed.

Expected result

Not enough money
300

In the real world

Game characters, bank accounts and web requests are commonly modelled as objects. Frameworks hand your code ready-made objects, so being able to read a class is useful even before you write large ones.

Common mistakes

  • Forgetting self as the first parameter of a method: calling it then raises a TypeError about the number of arguments.
  • Writing name = name instead of self.name = name in __init__. Without self., the value is a local variable that disappears when __init__ returns.
  • Calling a method without brackets: s1.is_good is the method itself, not its result.

Best practices

  • Set every attribute in __init__, so that the object is always complete.
  • Change an object's data through its methods.
  • Use a class when data and behaviour truly belong together, and a function when they do not.

Summary

A class describes data and behaviour, and each object has its own attributes. __init__ sets a new object up, self is the object being used, and assigning an object adds a second name for it.

Practice

Write a Rectangle class with width and height attributes and methods area() and perimeter(). Create two rectangles and print both results for each.

Quick check

1. What is self inside a method?
2. How many Student objects does the first example create?
3. After b = a and b.value = 5 (both Counter objects), what is a.value?

Key takeaways

  • A class joins data with the code that works on that data.
  • self.name stores a value on the object, and name alone is a local variable.
  • Assigning an object gives it a second name, not a copy.

Practice problems for this lesson

My notes

Write down what you want to remember from this lesson. Notes are saved on this device as you type, and appear on your dashboard.