A class in Python is a blueprint for creating objects — it bundles together data (attributes) and behavior (methods) into a single reusable unit. An object is a concrete instance created from that blueprint. If you've worked with strings or lists in Python, you've already been using objects: a string is an instance of the built-in str class, and it has both data (the characters) and methods (like .upper()).
Classes are the foundation of object-oriented programming (OOP) in Python. They let you model real-world things — a Car, a User, a BankAccount — as self-contained units instead of scattering related data and functions across your code.
Defining a Class and Creating Instances
You define a class with the class keyword. Inside it, methods are just functions, but their first parameter is always self, which refers to the specific instance the method is being called on.
class Dog:
# Class attribute — shared by every instance
species = "Canis familiaris"
def __init__(self, name, age):
# Instance attributes — unique to each object
self.name = name
self.age = age
def bark(self):
return f"{self.name} says Woof!"
# Creating two separate instances (objects) of Dog
dog1 = Dog("Rex", 3)
dog2 = Dog("Bella", 5)
print(dog1.bark())
print(dog2.name, "is", dog2.age, "years old")
print(dog1.species)
Output:
Rex says Woof!
Bella is 5 years old
Canis familiaris
Calling Dog("Rex", 3) runs the special __init__ method automatically — this is the constructor, and it's where you set up each object's starting state.
Instance Attributes vs Class Attributes
Notice species is defined directly inside the class body, outside any method — it's a class attribute, shared by every instance unless an instance overrides it. name and age, on the other hand, are instance attributes: each object gets its own independent copy, set through self inside __init__.
dog3 = Dog("Max", 2)
dog3.species = "Modified" # only changes dog3's own copy
print(dog1.species) # still the original class attribute
print(dog3.species) # the instance-level override
Output:
Canis familiaris
Modified
Calling Methods
Methods are called on an instance using dot notation, just like accessing an attribute. Python automatically passes the instance as the first argument (self), so you never pass it explicitly — dog1.bark() is really shorthand for Dog.bark(dog1) under the hood.
Classes become far more useful once you build on this foundation with a closer look at the constructor, and later with inheritance, which lets one class reuse and extend another's behavior. If you're coming from writing standalone functions, think of a class as a way to group related functions and the data they operate on into one cohesive object.
