Classes

1 min readUpdated January 9, 2026pythonoopclasses

A class is a blueprint; an instance (or object) is a concrete thing built from that blueprint, with its own independent state.

dog.py
class Dog:
def __init__(self, name: str):
self.name = name
self.tricks: list[str] = []
def learn_trick(self, trick: str) -> None:
self.tricks.append(trick)
rex = Dog("Rex")
rex.learn_trick("sit")
fido = Dog("Fido")
print(rex.tricks) # ['sit']
print(fido.tricks) # [] — completely separate state

__init__ (highlighted, line 2) is the constructor — it runs once per instance and sets up that instance’s own attributes. learn_trick (line 6) is an instance method: the first parameter, self, is always a reference to the specific object the method was called on.

Diagram showing one Dog class producing two independent instances, rex and fido
One class, many independent instances — each with its own state.

Classes exist in other languages too

The shape is the same everywhere: a constructor, instance state, instance methods.

class Dog:
def __init__(self, name: str):
self.name = name
def bark(self) -> str:
return f"{self.name} says woof!"
public class Dog {
private final String name;
public Dog(String name) {
this.name = name;
}
public String bark() {
return name + " says woof!";
}
}

Class attributes vs. instance attributes

class Dog:
species = "Canis familiaris" # class attribute — shared by every instance
def __init__(self, name: str):
self.name = name # instance attribute — unique per instance
print(Dog("Rex").species) # "Canis familiaris"
print(Dog("Fido").species) # "Canis familiaris" — same value, shared on the class

Mutable class attributes (lists, dicts) are a classic gotcha: since they’re shared, mutating one through an instance affects every instance. Prefer setting mutable defaults inside __init__.

Where this leads

Classes are the foundation for the rest of Python OOP — inheritance, @property, dunder methods, and dataclasses all build directly on the instance/class-attribute model shown here.