Python26 min read

Python Metaclasses

Understand what metaclasses are, why they exist, and how they can enforce rules or inject behavior at class creation time (with safer alternatives).

David Miller
July 24, 2025
4.5k125

Metaclasses are an advanced topic. You should learn them only after you are comfortable with:
- classes
- inheritance
- decorators
- class methods and static methods

      But once you understand them, you will see how frameworks like Django do powerful things automatically.
      
      ## The core idea
      
      - An object is created by a class.
      - A class is created by a **metaclass**.
      
      In Python, most classes are created by the built-in metaclass named `type`.
      
      ```python
      class MyClass:
          pass
      
      print(type(MyClass))  # <class 'type'>
      ```
      
      So yes, Python’s `type` is the “class that creates classes”.
      
      ## When metaclasses are useful
      
      Metaclasses are useful when you want to control class creation, for example:
      - enforce that a class must contain specific methods
      - automatically add attributes/methods to every class
      - register classes (plugin systems)
      - build ORM-like behavior
      
      ## Example 1: Inject a method into every class
      
      ```python
      class Meta(type):
          def __new__(cls, name, bases, attrs):
              # add a greet method to every class built with this metaclass
              def greet(self):
                  print(f"Hi, I am an instance of {name}")
              attrs["greet"] = greet
              return super().__new__(cls, name, bases, attrs)
      
      class User(metaclass=Meta):
          pass
      
      u = User()
      u.greet()
      ```
      
      Expected output:
      ```
      Hi, I am an instance of User
      ```
      
      ## Example 2: Enforce a rule (validation metaclass)
      
      Imagine you want every repository class to have a `save()` method.
      
      ```python
      class ValidationMeta(type):
          def __new__(cls, name, bases, attrs):
              if name != "BaseRepo" and "save" not in attrs:
                  raise TypeError(f"{name} must define a save() method")
              return super().__new__(cls, name, bases, attrs)
      
      class BaseRepo(metaclass=ValidationMeta):
          pass
      
      class UserRepo(BaseRepo):
          def save(self):
              print("Saving user")
      
      repo = UserRepo()
      repo.save()
      ```
      
      If someone forgets `save()`, Python raises the error at class creation time.
      
      ## Example 3: Singleton with metaclass
      
      ```python
      class Singleton(type):
          _instances = {}
      
          def __call__(cls, *args, **kwargs):
              if cls not in cls._instances:
                  cls._instances[cls] = super().__call__(*args, **kwargs)
              return cls._instances[cls]
      
      class Database(metaclass=Singleton):
          def __init__(self):
              self.connected = True
      
      db1 = Database()
      db2 = Database()
      print(db1 is db2)  # True
      ```
      
      ## Safer alternatives you should consider first
      
      Before metaclasses, usually you can solve problems using:
      - decorators
      - inheritance
      - class decorators
      - __init_subclass__ (modern and simpler)
      
      Metaclasses are powerful, but they can make code harder for other developers to read.
      
      ## Graph: class creation pipeline
      
      ```mermaid
      flowchart LR
        A[Metaclass (type)] --> B[Creates Class]
        B --> C[Class creates Objects]
        C --> D[Instances]
      ```
      
      ## Key points
      
      - Metaclass creates the class
      - Python default metaclass is type
      - Use only when you truly need class-creation control
      - Prefer simpler alternatives when possible
      
#Python#Advanced#OOP