W3docs

Python Classes/Objects

Learn how Python classes and objects work: define classes, use __init__, create instances, work with attributes and methods, and understand inheritance.

Python is an object-oriented programming (OOP) language, which means it organizes code around objects rather than functions alone. A class is the blueprint that describes what data an object holds and what it can do. An object is a specific instance created from that blueprint.

This chapter covers:

  • What classes and objects are, and why they matter
  • Defining a class with __init__, instance attributes, and methods
  • Class attributes versus instance attributes
  • Creating and using objects
  • Modifying and deleting attributes
  • Checking object types with isinstance()
  • A first look at inheritance

For a deeper dive into inheritance, see Python Inheritance. For more advanced OOP patterns, see Python Abstract Base Classes.

What Is a Class?

Think of a class as a cookie-cutter and an object as the cookie. You define the shape once (the class), then stamp out as many cookies (objects) as you need. Each object shares the same structure but holds its own data.

class Dog:
    pass  # an empty class — valid but not very useful yet

The class keyword followed by a name and a colon creates a new class. By convention, class names use CapWords (also called PascalCase): MyClass, BankAccount, HttpRequest.

The __init__ Method

The __init__ method (short for initialise) runs automatically every time you create a new object. It sets up the object's initial state by assigning values to its instance attributes.

class Dog:
    def __init__(self, name, age):
        self.name = name   # instance attribute
        self.age = age     # instance attribute

The first parameter is always self — it refers to the object being created. Python passes it automatically; you never supply it yourself.

Instance Attributes vs. Class Attributes

KindDefined insideBelongs toShared?
Instance attribute__init__ (via self)Each objectNo — each object has its own copy
Class attributeClass body (outside any method)The class itselfYes — all objects share one copy
class Dog:
    species = "Canis familiaris"  # class attribute — shared by all Dogs

    def __init__(self, name, age):
        self.name = name   # instance attribute
        self.age = age     # instance attribute

fido = Dog("Fido", 3)
bella = Dog("Bella", 5)

print(fido.species)    # Canis familiaris
print(bella.species)   # Canis familiaris  (same class attribute)
print(fido.name)       # Fido
print(bella.name)      # Bella             (different instance attributes)

Use a class attribute when a value is the same for every object of that type (e.g., the species of all Dogs). Use instance attributes for data that varies per object.

Defining Methods

A method is a function defined inside a class. Like __init__, it always takes self as its first parameter so it can access the object's own attributes.

class Dog:
    species = "Canis familiaris"

    def __init__(self, name, age):
        self.name = name
        self.age = age

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

    def description(self):
        return f"{self.name} is {self.age} years old."

You call a method on an object using dot notation — Python automatically passes the object as self:

fido = Dog("Fido", 3)
print(fido.bark())          # Fido says: Woof!
print(fido.description())   # Fido is 3 years old.

The __str__ Method

Python calls __str__ when you pass an object to print() or str(). Without it, you get an unhelpful address like <__main__.Dog object at 0x...>. Defining it makes debugging much easier.

class Dog:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __str__(self):
        return f"Dog(name={self.name!r}, age={self.age})"

fido = Dog("Fido", 3)
print(fido)   # Dog(name='Fido', age=3)

Creating and Using Objects

Creating an object is called instantiation. You call the class like a function, passing any arguments that __init__ expects (excluding self):

python— editable, runs on the server

You can create as many objects as you need from the same class — each is independent:

class Rectangle:
    def __init__(self, width, height=1):
        self.width = width
        self.height = height

    def area(self):
        return self.width * self.height

    def perimeter(self):
        return 2 * (self.width + self.height)

r1 = Rectangle(4, 3)
r2 = Rectangle(5)      # height defaults to 1

print(r1.area())        # 12
print(r1.perimeter())   # 14
print(r2.area())        # 5

Notice that height=1 provides a default value: if you omit the second argument, Python uses 1 automatically.

Modifying and Deleting Attributes

You can change or add attributes on an object after it has been created, and delete them with del:

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

p = Person("Alice", 30)
print(p.age)      # 30

p.age = 31        # modify an existing attribute
print(p.age)      # 31

p.email = "[email protected]"   # add a new attribute at runtime
print(p.email)    # [email protected]

del p.email       # delete the attribute
# print(p.email)  # would raise AttributeError

While Python allows adding attributes freely, it is cleaner to declare all attributes inside __init__ so the class's structure is obvious at a glance.

Checking Object Types

Use isinstance() to check whether an object is an instance of a particular class. It returns True for the class itself and any of its parent classes:

class Animal:
    pass

class Dog(Animal):
    pass

rex = Dog()
print(isinstance(rex, Dog))     # True
print(isinstance(rex, Animal))  # True  — Dog is a subclass of Animal
print(type(rex) is Dog)         # True
print(type(rex) is Animal)      # False — type() does not climb the hierarchy

Prefer isinstance() over type() is in most code because it correctly handles subclasses.

A First Look at Inheritance

Inheritance lets a new class reuse and extend the behaviour of an existing one. The new class (child or subclass) automatically gains all the attributes and methods of the parent:

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

    def speak(self):
        return f"{self.name} makes a sound."

class Dog(Animal):
    def speak(self):                     # override the parent method
        return f"{self.name} says: Woof!"

class Cat(Animal):
    def speak(self):
        return f"{self.name} says: Meow!"

dog = Dog("Rex")
cat = Cat("Whiskers")
print(dog.speak())             # Rex says: Woof!
print(cat.speak())             # Whiskers says: Meow!
print(isinstance(dog, Animal)) # True

Both Dog and Cat inherit __init__ from Animal, so they don't need to repeat it. They only override speak() to provide breed-specific behaviour.

For a full treatment of inheritance — including super(), multiple inheritance, and method resolution order — see Python Inheritance.

When Should You Use a Class?

Classes make most sense when:

  • You have data and behaviour that belong together (a bank account that knows how to deposit and withdraw).
  • You need multiple independent objects of the same type (many Dog objects, each with different names and ages).
  • You want to model real-world entities with a clear identity.

Simple utility functions that just transform input to output are often better as plain functions. Python does not require everything to be in a class.

Summary

ConceptWhat it does
classDefines a new type
__init__Initialises instance attributes when an object is created
selfRefers to the current object inside a method
Instance attributeData belonging to one specific object
Class attributeData shared across all objects of the class
MethodA function defined inside a class; always receives self
__str__Controls how print() displays the object
isinstance()Checks whether an object is an instance of a class or its subclasses
InheritanceLets a child class reuse and extend a parent class

Practice

Practice
What is the correct way to create a class in Python?
What is the correct way to create a class in Python?
Was this page helpful?