Skip to main content
Object-Oriented Programming (OOP) is a paradigm that groups related data (attributes) and behaviour (methods) into reusable blueprints called classes. An individual object built from a class is an instance. Python’s OOP model is highly flexible — classes are first-class objects, type checking is dynamic, and you have precise control over encapsulation and inheritance. This page walks you through everything from basic class definitions to advanced features like abstract base classes and class variables.

Classes and Instances

A class is a blueprint. An instance is a concrete object built from that blueprint.
Key concepts demonstrated above:
  • Class: Student
  • Object (instance): student1
  • Attributes: name, age
  • Methods: introduce(), study()
  • Constructor: __init__() initialises instance attributes

Attributes and Methods

Instance Methods

Functions inside a class that operate on a specific instance. They always accept self as the first parameter:

Class Attributes and @classmethod

Class attributes are shared by all instances. Class methods accept cls instead of self and are used for factory methods or modifying class-level state:

Static Methods (@staticmethod)

Static methods do not receive self or cls. They are plain utility functions grouped inside the class namespace:

Type Checking: type() vs isinstance()

Prefer isinstance() in most code. It respects the inheritance hierarchy and is the Pythonic way to check types.

Inheritance

Inheritance lets a child class inherit attributes and methods from a parent class, extending or overriding behaviour as needed:

Passing Arguments via __init_subclass__

You can pass configuration to a parent class at class-definition time using __init_subclass__:
This runs at import time — before any instances are created — and is the pattern used by ORMs like SQLAlchemy.

Encapsulation

Encapsulation restricts direct access to internal state to prevent accidental modification:
  • Protected (_name): Convention only — Python does not enforce it.
  • Private (__pin): Triggers name mangling (_ClassName__pin), making direct external access raise an AttributeError.

Properties

Properties let you attach validation logic to attribute access using @property getters and setters:

Abstract Classes

Abstract Base Classes (ABCs) define an interface contract — subclasses must implement every abstract method:

Introspection

Python provides built-in tools to inspect objects at runtime:

Type Annotations, Class Variables, and Instance Variables

Understanding what each declaration means is critical when working with Python, Pydantic, and dataclasses.

Type Annotation Only

A bare annotation describes the expected type but does not create an attribute:
Accessing Product.name raises AttributeError.

Instance Variables

Created when a value is assigned to self inside __init__:
Each object gets its own independent copy.

Class Variables

Shared by every instance. Annotate with ClassVar to make intent explicit:

Behaviour Across Frameworks

Always use ClassVar when declaring class-level constants. It prevents Pydantic and dataclasses from accidentally treating the attribute as a model field.