Skip to main content
Python’s object-oriented programming model is extremely dynamic. Classes are not just templates; they are first-class objects created at runtime. This section explores how to harness metaclasses, dunder methods, and dynamic class creation.

1. Abstract Base Classes (ABC)

An Abstract Base Class (ABC) allows you to define a set of methods that subclasses must implement. This enforces a strict interface or API contract in your code. We use the built-in abc module, ABC subclass, and @abstractmethod decorator:

2. Classes are Objects (Metaclasses)

In Python, everything is an object, including classes themselves. When you write a class statement, Python executes it and creates a class object in memory. By default, all classes are instances of the metaclass type:

Dynamic Class Creation with type()

Because classes are objects, you can create them dynamically using the three-argument form of the built-in type(name, bases, dict) constructor:

3. Special Attributes: __dict__ and __annotations__

Python class objects maintain internal dictionaries to manage namespaces and metadata:

__dict__

The namespace dictionary containing all local attributes, functions, and methods defined directly on the object/class.

__annotations__

A dictionary that stores the type hints defined on the class attributes or parameters. This dictionary is crucial for libraries performing runtime type checks.

4. Dunder Methods (Magic Methods)

Dunder (Double-Underscore) methods allow you to hook into Python’s built-in behaviors:
  • __new__: The static creator method responsible for allocating memory and returning a new instance of a class. It runs before __init__.
  • __init__: The initializer method that configures the fields on the instance returned by __new__.
  • __call__: Allows instances of your class to be called like functions.
  • __repr__ / __str__: Control how your object is converted to a string.

5. Class Creation Stages

When a class definition is executed, Python goes through distinct stages to build the class object using its metaclass: To intercept this creation pipeline, you define a custom metaclass subclassing type.

6. Real-World Framework Implementations

Advanced OOP mechanics are the backbone of modern Python frameworks:

SQLAlchemy (Declarative Bases)

SQLAlchemy uses metaclasses to inspect class attributes and map them automatically to relational database columns:
  • When you define a class inheriting from DeclarativeBase, SQLAlchemy’s metaclass intercepts the class definition.
  • It parses class attributes (like id = Column(Integer)) and reads the class name to register database tables.
  • It maps the class attributes to query descriptors, meaning when you assign user.name = "Rahul", it tracks database updates dynamically.

FastAPI / Pydantic (BaseModel)

Pydantic uses metaclasses and annotations to perform automatic serialization and data validation:
  • When a class inheriting from Pydantic’s BaseModel is created, Pydantic’s metaclass reads __annotations__ at runtime.
  • It builds validator functions based on types (e.g. age: int generates an integer parser).
  • FastAPI intercepts HTTP requests, passes them to Pydantic schemas, and raises detailed parsing errors if values don’t match, all before your endpoint function runs.

Practice & Exercises

To reinforce what you’ve learned in this section (Abstract Classes, Metaclasses, and Dunder hooks), practice with these interactive notebooks:

Follow-Along Practice

Practice creating Abstract classes, hook new, dynamically create classes, and inspect annotations.💻 VS Code | 🚀 Colab | 📥 Download

Practice Exercises

Test your advanced OOP understanding with custom exercises on interface enforcement and metaclass inspectors.💻 VS Code | 🚀 Colab | 📥 Download

What’s next?

Learn about how to validate your data using Type Hints, Dataclasses, and Pydantic!

Introduction to Pydantic

Learn runtime type validation and Pydantic models