Learn / Programming / Python / Classes and Objects

Python · Lesson 9 of 15

Classes and Objects

Model data with classes, __init__, methods, and self.

  • Intermediate
  • 18 min read
  • 3 objectives

Before this lessonLesson 8: Comprehensions and Iteration

What you will learn

  • Define a class with __init__
  • Add instance methods
  • Understand self

A class is a blueprint that bundles data (attributes) with the functions that work on it (methods). An object, or instance, is one thing built from that blueprint. Classes help when several related values travel together, such as a bank account with an owner and a balance, and when behavior belongs with that data.

The idea behind classes

So far you have stored data in variables and behavior in functions, kept separately. When a program models real things such as a bank account, a player, an order, you find yourself passing the same group of values around. A class bundles the data and the functions that work on it into one unit. Picture a cookie cutter: the class is the cutter (the blueprint); each object is a cookie made from it. Every cookie has the same shape but its own icing.

Your first class

__init__ runs automatically when you create an instance and sets up its starting state. The first parameter of every method is self, which refers to the specific object the method is being called on. You do not pass it yourself; Python does.

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

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

acct = BankAccount("Amar", 100)
acct.deposit(50)
print(acct.owner, acct.balance)
Output
Amar 150

Each object has its own state

Two instances of the same class do not share attribute values. Changing one account leaves the other untouched.

a = BankAccount("Ann", 10)
b = BankAccount("Bob", 500)
a.deposit(5)
print(a.balance, b.balance)
Output
15 500

Making objects printable

Special methods with double underscores customize behavior. __repr__ controls how an object is displayed, which makes debugging much easier than the default <BankAccount object at 0x...>.

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

    def __repr__(self):
        return f"BankAccount({self.owner!r}, {self.balance})"

print(BankAccount("Amar", 100))
Output
BankAccount('Amar', 100)

Inheritance in one minute

A subclass reuses and extends another class. Put the parent in parentheses and call super() to run its logic.

class SavingsAccount(BankAccount):
    def add_interest(self, rate):
        self.deposit(self.balance * rate)

s = SavingsAccount("Amar", 1000)
s.add_interest(0.05)
print(s.balance)
Output
1050.0

Anatomy of a class, line by line

class Counter:
    def __init__(self, start=0):
        self.value = start        # data stored on this object

    def increment(self):          # behavior
        self.value += 1
        return self.value


a = Counter()
b = Counter(10)
a.increment()
a.increment()
b.increment()
print(a.value, b.value)
Output
2 11
  • class Counter: defines the blueprint.
  • __init__ runs automatically when you create an object. It sets up the starting data.
  • self means "this particular object". Every method receives it first; you do not pass it yourself.
  • a and b are separate objects, so their values do not affect each other.

Keeping data valid

A class is a good place to protect rules. Here a bank account refuses to go below zero, and every caller gets the same protection automatically.

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

    def withdraw(self, amount):
        if amount > self.balance:
            raise ValueError("insufficient funds")
        self.balance -= amount

acct = Account("Ada", 100)
acct.withdraw(30)
print(acct.balance)
try:
    acct.withdraw(500)
except ValueError as err:
    print("Error:", err)
Output
70
Error: insufficient funds

Making objects print nicely

class Book:
    def __init__(self, title, pages):
        self.title = title
        self.pages = pages

    def __str__(self):
        return f"{self.title} ({self.pages} pages)"

print(Book("Dune", 412))
Output
Dune (412 pages)

Class attributes and methods that do not need an object

class Circle:
    PI = 3.14159            # shared by all circles

    def __init__(self, r):
        self.r = r

    def area(self):
        return Circle.PI * self.r ** 2

    @staticmethod
    def diameter(r):
        return 2 * r

print(Circle(2).area())
print(Circle.diameter(5))
Output
12.56636
10

Key takeaways

  • A class is a blueprint; an object is one thing built from it.
  • __init__ sets up each object; self refers to the current object.
  • Methods are functions that belong to the class and work on self.
  • Use classes to keep related data and behavior, and its rules, in one place.
# Write your solution here
Up next · Lesson 10Inheritance and Special MethodsReuse behavior with subclasses, override methods, and make objects print and compare nicely.