Skip to content
Laviyx Learn

Try

Python course menu

Python Classes Explained: Your First Steps in Object-Oriented Programming

Learn Python classes from scratch: what a class is, define one with class, __init__ and self, add methods, class vs instance attributes, and readable printing with __str__ and __repr__.

Intermediate9 min readUpdated
On this page

So far you have stored data in variables, lists and dictionaries, and written separate functions to work with it. Object-oriented programming (OOP) bundles the data and the functions that work on it together into objects. A class is the blueprint that describes what those objects contain and can do.

Why classes?#

Imagine a banking program. Each account has an owner and a balance, and can accept deposits and withdrawals. You could use a dictionary plus separate functions, but a class keeps everything about "a bank account" in one place:

  • attributes: the data each object holds (owner, balance)
  • methods: functions that belong to the object (deposit(), withdraw())

One class can create any number of independent objects, or instances, just as one house blueprint can build many houses.

Defining a class#

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

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

rex = Dog("Rex", "Labrador")
bella = Dog("Bella", "Beagle")

print(rex.bark())
print(bella.name, bella.breed)
print(type(rex).__name__)
Output
Rex says woof!
Bella Beagle
Dog

Piece by piece:

PartMeaning
class Dog:defines a new class; class names use PascalCase
__init__the constructor: runs automatically when an object is created
selfthe object being created or used
self.name = namestores a value on this object as an attribute
def bark(self):a method: a function that belongs to the class
Dog("Rex", "Labrador")creates an instance, calling __init__ with these arguments

What is self?#

self is the object the method is working on. When you call rex.bark(), Python automatically passes rex as self. That is how one bark method can produce "Rex says woof!" for one dog and "Bella says woof!" for another.

You never pass self yourself; Python does it. But every method must list it as its first parameter.

A more useful class#

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

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

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

acc = BankAccount("Asha", 1000)
print(acc.deposit(500))
print(acc.withdraw(300))
print(acc.owner, acc.balance)

try:
    acc.withdraw(5000)
except ValueError as e:
    print(e)
Output
1500
1200
Asha 1200
Insufficient funds

The rules about balances live inside the class, next to the data they protect.

Class attributes vs instance attributes#

  • Instance attributes (set with self.x = ...) belong to one object.
  • Class attributes (set directly in the class body) are shared by all objects of the class.
Python
class Dog:
    species = "Canis familiaris"     # class attribute: shared

    def __init__(self, name):
        self.name = name             # instance attribute: per object

a = Dog("Rex")
b = Dog("Bella")
print(a.species, b.species, Dog.species)
print(a.name, b.name)
Output
Canis familiaris Canis familiaris Canis familiaris
Rex Bella

A class attribute can also count how many objects have been created:

Python
class Counter:
    count = 0
    def __init__(self):
        Counter.count += 1

Counter(); Counter(); Counter()
print(Counter.count)
Output
3

Printing objects nicely#

By default, printing an object is not very helpful:

Python
print(rex)
Output
<__main__.Dog object at 0x0000024A616D1400>

(The address differs on every run.) Define __str__ for a friendly description and __repr__ for a developer-oriented one:

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

    def __str__(self):
        return f"Dog named {self.name}"

    def __repr__(self):
        return f"Dog({self.name!r})"

rex = Dog("Rex")
print(rex)
print([rex])
Output
Dog named Rex
[Dog('Rex')]

print() uses __str__; containers like lists and the interactive shell use __repr__. Methods with double underscores on both sides are called special or dunder methods; Python calls them for you in specific situations.

Common mistakes#

Practice#

Practice exercise

Write a Rectangle class with width and height, and methods area(), perimeter() and is_square(). Test it with a 4 × 6 rectangle and a 5 × 5 square.

Show hint

Store both values in __init__ with self.. Each method uses self.width and self.height.

Show solution
Python
class Rectangle:
    def __init__(self, width, height):
        self.width = width
        self.height = height

    def area(self):
        return self.width * self.height

    def perimeter(self):
        return 2 * (self.width + self.height)

    def is_square(self):
        return self.width == self.height

r = Rectangle(4, 6)
s = Rectangle(5, 5)
print(r.area(), r.perimeter(), r.is_square())
print(s.area(), s.is_square())
Output
24 20 False
25 True

Key takeaway#

Finished this lesson?