Python Classes and Objects: A Practical Beginner Guide
Table of Contents
If classes and objects still feel slippery, you’re not crazy. Most tutorials either go too abstract or drown you in weird examples. The practical way to learn OOP is simple: understand how data and behavior stick together, then build small objects that are easy to reason about.
All the content from our Boot.dev courses are available for free here on the blog. This one is the “Classes and Objects” chapter of Learn OOP in Python. If you want to try the far more immersive version of the course, do check it out!
What Is a Class?
A class is a custom type. Think of it as a blueprint that defines what data exists and what actions are allowed.
You already use built-in types like str, int, and list. A class lets you define your own type when those built-ins aren’t enough.
class Archer:
health = 40
arrows = 10
print(Archer.health) # 40
You could model the same thing with a dictionary, but classes give you clearer structure as your program grows. This becomes especially useful once behavior enters the picture. If you need a quick refresher on basic function shape before methods, review Python functions.
What Is an Object?
An object is a specific instance of a class. The class is the blueprint, the object is the thing you actually use.
# Archer is a class: a blueprint for what an archer is.
class Archer:
health = 40
arrows = 10
legolas = Archer() # legolast is an object
bard = Archer() # bard is another object
print(legolas.health) # 40
print(bard.arrows) # 10
Instantiation is just calling the class like a function: Archer(). Every object has its own identity, and later, once you move data into instance variables, each object can have different values.
This is a big shift from storing everything in loose variables. You’re not just naming values anymore like in variables, you’re bundling related values and behavior into one unit.
Why Use Methods Instead of Plain Functions?
A method is just a function defined inside a class. The advantage is locality: behavior that belongs to the object lives with the object’s data.
class Soldier:
health = 5
def take_damage(self, damage):
self.health -= damage
unit = Soldier()
unit.take_damage(2)
print(unit.health) # 3
You can absolutely keep using plain functions. In fact, explicit functional programming style is often cleaner for simple transformations. But when behavior is tightly coupled to an object’s state, methods reduce mental overhead and make APIs feel natural.
What Does self Mean in a Method?
self is the object receiving the method call. Python passes it implicitly as the first argument.
This line:
unit.take_damage(2)
is conceptually similar to:
Soldier.take_damage(unit, 2)
That’s why self must appear in method signatures. It’s not a keyword, just a naming convention documented in the Python glossary, but you should always use it.
If this feels odd at first, good. It clicks quickly once you build a few classes.
How Do Constructors Work?
A constructor lets each new object start with configurable values instead of hardcoded defaults. In Python, this is __init__.
class Soldier:
def __init__(self, name, armor, num_weapons):
self.name = name
self.armor = armor
self.num_weapons = num_weapons
gimli = Soldier("Gimli", 5, 1)
print(gimli.name) # Gimli
Constructors are usually safer because they avoid accidental shared defaults and make object setup obvious. They also make tests easier to write because each object can be initialized to exactly the scenario you want. Pair this with assertions and your object tests stay tiny and clear.
What Is the Difference Between Class and Instance Variables?
Instance variables belong to one object. Each object gets its own value.
Class variables belong to the class itself. Every object shares that value.
class Dragon:
kingdom = "north" # class variable
def __init__(self, name, element):
self.name = name # instance variable
self.element = element # instance variable
smaug = Dragon("Smaug", "fire")
viserion = Dragon("Viserion", "ice")
print(smaug.kingdom, viserion.kingdom) # north north
print(smaug.element, viserion.element) # fire ice
Dragon.kingdom = "east"
print(smaug.kingdom, viserion.kingdom) # east east
Shared mutable state is where bugs hide. If changing one object unexpectedly changes others, you probably wanted an instance variable instead.
As a beginner default, use instance variables first. Use class variables only when you intentionally want one shared value across all instances.
How Do You Create Multiple Objects Without Chaos?
Treat classes as templates and keep each object focused. If an object needs to know too much or do too much, split responsibilities.
class Wall:
def __init__(self, depth, height, width):
self.depth = depth
self.height = height
self.width = width
self.volume = depth * height * width
wall_a = Wall(1, 2, 3)
wall_b = Wall(4, 5, 6)
print(wall_a.volume, wall_b.volume) # 6 120
As programs grow, object collections become common. A small manager object plus a list of instances is often enough. You don’t need enterprise architecture on day one. Start simple, iterate, and keep behavior near data.
What Should You Learn After Classes and Objects?
Next up is encapsulation: hiding implementation details so your public API is easier to use correctly. That’s where OOP gets really practical.
If you want to keep momentum, continue through Learn Object Oriented Programming in Python and then apply it in real backend projects on the Back-end Developer Path in Python and Go.
Frequently Asked Questions
What is the difference between a class and an object?
A class is a blueprint that defines data and behavior, while an object is a specific instance created from that blueprint.
Why does Python use self in methods?
self refers to the specific object calling the method, so the method can read and update that objects state.
Do I always need __init__ in a class?
No, but you usually want it when objects need configurable starting values or setup logic.
When should I use class variables?
Use class variables only for truly shared state across all instances. Prefer instance variables for most application data.
Are methods just functions?
Yes. A method is a function attached to a class, and Python passes the calling instance as the first argument.
Related Articles
Clean Code in Python: Write Readable, Maintainable Code
Mar 20, 2026 by Lane Wagner - Boot.dev co-founder and backend engineer
If you ask ten developers for a definition of clean code, you will get twelve answers and one argument in the comments. Still, most of us agree on the practical goal: write code that other humans can understand quickly and change safely. That matters way more than writing clever one-liners that only make sense to your past self at 2 AM.
Python Encapsulation vs Abstraction: What Matters
Mar 20, 2026 by Lane Wagner - Boot.dev co-founder and backend engineer
If classes and objects are the “what” of OOP, encapsulation and abstraction are the “how.” They’re how you keep code understandable after the project gets big, your team grows, and six months pass. They sound similar because they’re close cousins, but they solve slightly different pains.
Python Inheritance: When to Use It and Skip It
Mar 20, 2026 by Lane Wagner - Boot.dev co-founder and backend engineer
Inheritance is one of those OOP tools that feels magical on day one and dangerous on day thirty. Used well, it removes duplication and keeps models clean. Used badly, it creates class trees no one wants to touch.
Python Polymorphism: One Interface, Many Behaviors
Mar 20, 2026 by Lane Wagner - Boot.dev co-founder and backend engineer
Polymorphism is where OOP starts to feel truly powerful. You stop writing giant if type == ... trees and start trusting shared interfaces. Different objects respond to the same method call in different ways, and your calling code stays clean.