Object-Oriented ProgrammingIntermediate9 min39 / 63

Classes & Objects

Learn how to build your own custom data types using classes — bundling data and behavior together in one tidy package.

So far you have used Python's built-in types: strings, lists, numbers. But what if you want to create your own type — something that models a real-world thing, like a dog, a bank account, or a player in a game?

That is exactly what classes are for. A class lets you define a brand-new kind of object with its own data and its own actions.

See it in action

Visual walkthrough1 / 5
1

Build Your Own Data Types

Python gives you strings, lists, and numbers — but what if you need a Dog, a BankAccount, or a Player? A class lets you invent any type you need.

Classes bundle data and behavior into one tidy, reusable package.
Think of it like

Cookie Cutter vs. Cookies

A class is like a cookie cutter — it is just the shape. An object (also called an instance) is an actual cookie made from that cutter.

You define the class once. Then you can stamp out as many individual objects as you like, each with its own data.

#Defining Your First Class

Use the class keyword followed by the class name (by convention, use CapitalizedWords). The body of the class is indented, just like a function.

Even an empty class can be instantiated.
class Dog:
    pass  # an empty class for now

my_dog = Dog()  # create an instance
print(type(my_dog))

Dog() with parentheses creates (instantiates) a new object from the class. The variable my_dog now holds that object. type() confirms it belongs to your Dog class.

#Attributes — Storing Data on an Object

An attribute is a piece of data attached to a specific object. You define attributes inside a special method called __init__ (pronounced "dunder init"), which Python calls automatically whenever you create a new instance.

Think of __init__ as the "set up" instructions that run the moment a cookie is stamped out.

Each instance keeps its own copy of the attributes.
class Dog:
    def __init__(self, name, breed):
        self.name = name
        self.breed = breed

dog1 = Dog("Bella", "Labrador")
dog2 = Dog("Max", "Poodle")

print(dog1.name)
print(dog2.breed)
Note

What is `self`?

self is a reference to the specific object being worked on right now.

When you write dog1 = Dog("Bella", "Labrador"), Python secretly passes dog1 as the first argument. self.name = name means "store name on this particular dog".

You must include self as the first parameter of every method — Python handles passing it automatically.

#Methods — Giving Objects Behavior

A method is a function that lives inside a class. It describes what an object can do. Methods always take self as their first parameter so they can access the object's own data.

Call a method using dot notation: object.method()
class Dog:
    def __init__(self, name, breed):
        self.name = name
        self.breed = breed

    def bark(self):
        print(f"{self.name} says: Woof!")

    def describe(self):
        print(f"{self.name} is a {self.breed}.")

dog1 = Dog("Bella", "Labrador")
dog1.bark()
dog1.describe()

Notice that when you call dog1.bark() you do not pass self — Python does that for you. You only write self in the method definition, not when you call it.

#Each Instance is Independent

Every object created from a class has its own separate copy of the attributes. Changing one object does not affect another.

Modifying dog1 leaves dog2 completely untouched.
dog1 = Dog("Bella", "Labrador")
dog2 = Dog("Max", "Poodle")

dog1.name = "Bella-Boo"  # change only dog1

dog1.describe()
dog2.describe()

#A More Complete Example

Here is a slightly bigger class to show how attributes and methods work together naturally.

The class bundles the balance (data) with deposit/withdraw (behavior).
class BankAccount:
    def __init__(self, owner, balance=0):
        self.owner = owner
        self.balance = balance

    def deposit(self, amount):
        self.balance += amount
        print(f"Deposited ${amount}. New balance: ${self.balance}")

    def withdraw(self, amount):
        if amount > self.balance:
            print("Not enough funds!")
        else:
            self.balance -= amount
            print(f"Withdrew ${amount}. New balance: ${self.balance}")

account = BankAccount("Alice", 100)
account.deposit(50)
account.withdraw(30)
account.withdraw(200)
Common mistake

Forgetting `self` in a Method

A very common mistake is forgetting self as the first parameter of a method:

``python class Dog: def bark(): # WRONG — missing self print("Woof!") ``

When you call dog1.bark(), Python will raise a TypeError complaining about too many arguments. Always start every method with self.

Tip

Why Bother with Classes?

Without classes, a program managing 50 dogs would need 50 separate variables for names, 50 for breeds, and so on — hard to keep track of.

With a class, each dog carries all its own data in one place, and you get the same helper methods for free on every instance. Code stays organized and reusable.

Quick check

What is the purpose of the `__init__` method in a class?

Key takeaways

  • A **class** is a blueprint; an **object** (instance) is a real thing built from that blueprint.
  • `__init__` runs automatically when you create an instance — use it to set up attributes with `self.attribute = value`.
  • `self` always refers to the specific object a method is currently working on.
  • Methods are just functions inside a class — they give objects behavior and always take `self` as their first parameter.
  • OOP keeps related data and behavior bundled together, making code easier to read, reuse, and maintain.
Practice challenges
Test yourself · earn XP
0/4
Predict the output#1

What does this code print?

predict-output
class Dog:
    def __init__(self, name, breed):
        self.name = name
        self.breed = breed

    def bark(self):
        print(f"{self.name} says: Woof!")

dog1 = Dog("Bella", "Labrador")
dog2 = Dog("Max", "Poodle")
dog1.bark()
dog2.bark()
Fix the bug#2

This code has a bug. What is wrong?

fix-bug
class Dog:
    def bark():
        print("Woof!")

dog = Dog()
dog.bark()
Fill in the blank#3

Complete the `__init__` method so that each Cat stores its name as an attribute.

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

cat = Cat("Luna")
print(cat.name)
Reorder the lines#4

Put these lines in the right order to define a BankAccount class, create an instance, and deposit money.

1
    def __init__(self, owner):
2
        self.owner = owner
3
account.balance += 50
4
class BankAccount:
5
        self.balance = 0
6
print(account.balance)
7
account = BankAccount("Alice")
Your turn
Practice exercise

Create a class called Cat with the attributes name and color. Give it two methods: meow() which prints "<name> says: Meow!", and describe() which prints "<name> is a <color> cat." Then create two different Cat instances and call both methods on each.

Try it live — edit the code and hit Run to execute real Python:

solution.py · editable