Classes and Objects
Model real-world things as objects using class, __init__, methods, and attributes.
What you'll learn
- Define a class with an __init__ method and instance attributes
- Create instances of a class and call their methods
- Explain what self refers to inside an instance method
Prerequisites
Explanation
So far, data (variables, lists, dicts) and behavior (functions) have been separate. A class lets you bundle both together into a single reusable blueprint for creating objects — Python's word for instances of a class.
Defining a class. The class keyword introduces a class, conventionally named in CapitalizedWords:
class BankAccount:
def __init__(self, owner, balance=0):
self.owner = owner
self.balance = balance
init and self. __init__ is a special method Python calls automatically whenever you create a new instance, such as BankAccount("Riya", balance=100). Its job is to set up that instance's starting state. Every method you define inside a class — __init__ included — takes self as its first parameter. self refers to this particular instance: the one the method was actually called on. Writing self.owner = owner stores owner as an attribute on this instance specifically, so two different BankAccount objects can hold two completely different owners and balances without interfering with each other.
Creating instances. Calling a class like a function — BankAccount("Riya", balance=100) — runs __init__ and hands back a new object. That object is an instance of the class; you can create as many independent instances as you like from one class definition.
Methods. Functions defined inside a class (besides __init__) are called methods, and they operate on a particular instance's data through self. Calling account.deposit(50) is Python's shorthand for "run the deposit method with self bound to account" — you never pass self explicitly; Python fills it in for you based on which object you called the method on.
Why bother? Once you have more than a couple of related pieces of data plus operations on them, passing everything around as separate loose variables and functions gets unwieldy fast. A class keeps an object's data and the operations that make sense on that data living in one place, and every instance you create automatically gets its own independent copy of that data. This is the same idea behind almost every library and framework you'll use later — a database connection, a web request, an AI chat session are all commonly represented as objects with methods, exactly like the small examples here.
A note on mutable defaults. Just as with regular functions, avoid using a mutable value like [] or {} as a default argument to __init__ — because default argument values are created only once, all instances that rely on the default would end up silently sharing the exact same list or dict, rather than each getting their own.
Example
A BankAccount class with __init__, deposit, and withdraw methods, used to create and update one instance.
class BankAccount:
"""A simple bank account with a balance and an owner name."""
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
account = BankAccount("Riya", balance=100)
account.deposit(50)
account.withdraw(30)
print(f"{account.owner}'s balance: {account.balance}")Try it yourself
Create a second account for a different owner, then deposit and withdraw different amounts.
Code editor. Press Escape then Tab to leave the editor if keyboard focus becomes trapped. Press Control+Shift+M inside the editor to toggle Tab-key focus trapping.
Guided exercise
Guided exercise
Complete the perimeter method so it returns 2 * (width + height).
Checks: box.area() returns 24 · box.perimeter() returns 20 · plus 1 hidden check
Code editor. Press Escape then Tab to leave the editor if keyboard focus becomes trapped. Press Control+Shift+M inside the editor to toggle Tab-key focus trapping.
Stuck? Get a hint.
Independent exercise
Independent exercise
Define a Counter class: __init__(self, start=0) stores start as self.value; increment(self, amount=1) adds amount to self.value and returns it; reset(self) sets self.value to 0 and returns it.
Checks: Counter() starts at value 0 · increment() with no argument adds 1 · increment(5) adds 5 · plus 2 hidden checks
Code editor. Press Escape then Tab to leave the editor if keyboard focus becomes trapped. Press Control+Shift+M inside the editor to toggle Tab-key focus trapping.
Stuck? Get a hint.
Common mistakes
- Forgetting self as the first parameter of an instance method, which causes a TypeError when the method is called.
- Referring to width or height directly inside a method instead of self.width or self.height, causing a NameError.
- Confusing the class itself (Rectangle) with an instance of it (box = Rectangle(4, 6)) — only instances have their own attribute values.
- Using a mutable default argument in __init__ (like def __init__(self, items=[])), which is shared across every instance that relies on the default.
Knowledge check
Takeaway
A class bundles data and behavior into a reusable blueprint; each instance you create gets its own independent copy of that data, accessed through self.
Summary
Classes group related data and behavior together. __init__ runs automatically when a new instance is created and sets up that instance's attributes via self; other methods defined in the class operate on a specific instance's data the same way. Each instance is independent, and avoiding mutable default arguments keeps that independence intact.
References
Your notes
Notes save automatically.
Finished this lesson?
Mark it complete to track your progress and schedule a future review.
AI tutor
The optional AI tutor isn't enabled in this deployment. All lessons, exercises, quizzes, and search work fully without it.