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
— step through the idea, then dive into the details below.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.
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.
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.
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)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.
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.
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.
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)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.
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.
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.
What does this code print?
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()This code has a bug. What is wrong?
class Dog:
def bark():
print("Woof!")
dog = Dog()
dog.bark()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)
Put these lines in the right order to define a BankAccount class, create an instance, and deposit money.
def __init__(self, owner):
self.owner = owner
account.balance += 50
class BankAccount:
self.balance = 0
print(account.balance)
account = BankAccount("Alice")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: