Python Classes & Objects
A class is a blueprint, and an object is a thing built from that blueprint. Classes bundle data (attributes) with the functions that work on it (methods). Page objects in test automation, models in web apps and most libraries you use are built from classes.
- Define a class and create objects
- Use __init__ and self correctly
- Class vs instance attributes
- Special methods, classmethods and dataclasses
Define a class and create objects
class Dog: pass rex = Dog()bella = Dog()print(type(rex).__name__, rex is bella)Dog False
Each call to Dog() creates a new, separate object (an instance) of the class.
__init__ and self
__init__ runs automatically when an object is created. Use it to set the object’s starting attributes. self is the object being created; Python passes it for you.
class Account: def __init__(self, owner, balance=0): self.owner = owner # instance attribute self.balance = balance acc1 = Account("Asha", 500)acc2 = Account("Ravi")print(acc1.owner, acc1.balance)print(acc2.owner, acc2.balance)Asha 500 Ravi 0
self is just the conventional name for the first parameter. Every method needs it, because it is how the method reaches the object’s data.
Methods
Methods are functions defined inside a class. Call them on an object with a dot.
class Account: def __init__(self, owner, balance=0): self.owner = owner self.balance = balance def deposit(self, amount): if amount <= 0: raise ValueError("Deposit must be positive") self.balance += amount return self.balance def withdraw(self, amount): if amount > self.balance: print("Insufficient funds") return self.balance self.balance -= amount return self.balance acc = Account("Asha", 100)print(acc.deposit(50))print(acc.withdraw(500))print(acc.withdraw(30))150 Insufficient funds 150 120
acc.deposit(50) is really Account.deposit(acc, 50): the object goes into self.
Class attributes vs instance attributes
An attribute set on the class is shared by all objects. One set on self belongs to a single object.
class Employee: company = "SQA Tools" # class attribute: shared count = 0 def __init__(self, name): self.name = name # instance attribute: per object Employee.count += 1 a = Employee("Asha")b = Employee("Ravi")print(a.company, b.company, Employee.count)print(a.name, b.name)SQA Tools SQA Tools 2 Asha Ravi
__str__ and __repr__
Special methods (with double underscores) let your objects work with built-in functions. __str__ controls print(); __repr__ controls how the object looks in lists and the shell.
class Product: def __init__(self, name, price): self.name = name self.price = price def __str__(self): return f"{self.name} (Rs {self.price})" def __repr__(self): return f"Product({self.name!r}, {self.price})" p = Product("Mouse", 349)print(p)print([p, Product("Pen", 10)])Mouse (Rs 349)
[Product('Mouse', 349), Product('Pen', 10)]Other useful special methods include __len__, __eq__ and __lt__:
class Playlist: def __init__(self, *songs): self.songs = list(songs) def __len__(self): return len(self.songs) def __eq__(self, other): return self.songs == other.songs p1 = Playlist("a", "b")p2 = Playlist("a", "b")print(len(p1), p1 == p2, p1 is p2)2 True False
classmethod and staticmethod
- A
@classmethodreceives the class (cls) instead of an object. It is often used as an alternative constructor. - A
@staticmethodreceives neither; it is a plain function grouped with the class.
class Temperature: def __init__(self, celsius): self.celsius = celsius @classmethod def from_fahrenheit(cls, f): return cls(round((f - 32) * 5 / 9, 1)) @staticmethod def is_freezing(celsius): return celsius <= 0 t = Temperature.from_fahrenheit(98.6)print(t.celsius, Temperature.is_freezing(t.celsius))37.0 False
Dataclasses
For classes that mainly hold data, @dataclass writes __init__, __repr__ and __eq__ for you:
from dataclasses import dataclass, field @dataclassclass TestCase: name: str priority: int = 3 tags: list = field(default_factory=list) tc = TestCase("login works", 1, ["smoke"])print(tc)print(tc == TestCase("login works", 1, ["smoke"]))TestCase(name='login works', priority=1, tags=['smoke']) True
Check your understanding
Predict the output
class Counter: total = 0 def __init__(self): self.mine = 0 def hit(self): self.mine += 1 Counter.total += 1 a, b = Counter(), Counter()a.hit(); a.hit(); b.hit()print(a.mine, b.mine, Counter.total)2 1 3
mine is per object, so a has 2 and b has 1. total lives on the class and counts all three hits.
Quick quiz
1. What is self in a method?
self refers to the instance. The name is a strong convention, not a keyword.
2. When does __init__ run?
Account("Asha") creates the object and then calls __init__ on it.
3. Which method controls what print(obj) shows?
print() uses __str__, falling back to __repr__.
4. What does a @classmethod receive as its first argument?
Conventionally named cls; it is useful for alternative constructors.
Exercise: rectangle class
Create a Rectangle class with width and height, methods area() and perimeter(), and a __str__ that prints like Rectangle 4x6.
Rectangle(4, 6)
Rectangle 4x6 Area: 24 Perimeter: 20
Hint 1
Store width and height on self in __init__.
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 __str__(self): return f"Rectangle {self.width}x{self.height}" r = Rectangle(4, 6)print(r)print("Area:", r.area())print("Perimeter:", r.perimeter())Rectangle 4x6 Area: 24 Perimeter: 20
__init__ saves the two sides on the object, and each method reads them back through self. __str__ makes print(r) readable.
Program Practice
48 Python OOP Programs
Every program has a step-by-step explanation, colour-coded code and its real output.
Python classes and objects FAQ
What is the difference between a class and an object?
A class is the definition (the blueprint). An object is a concrete instance created from it, with its own attribute values.
Why do Python methods need self?
self is how a method accesses the object it was called on. Python passes the object automatically as the first argument.
What is __init__ in Python?
It is the initialiser that runs right after an object is created. It sets up the object’s attributes.
When should I use a dataclass?
When a class mainly stores data. @dataclass generates the boilerplate methods and keeps the class short and readable.