Python  

What are Metaclasses in Python?

đź§© Everything is an Object in Python

In Python, almost everything is treated as an object. This includes not only variables and data structures but also functions and classes. Since classes are objects too, they can be:

  • Passed as arguments

  • Stored in variables

  • Created dynamically at runtime

Most importantly, this object-oriented nature allows classes to generate other classes. The special classes that do this are called metaclasses.

🔑 What is a Metaclass?

Just as a class defines how an object behaves, a metaclass defines how a class behaves. By default, the metaclass for all Python classes is type.

  • Objects are created by classes.

  • Classes are created by metaclasses.

👉 In short, metaclasses are the blueprints for classes.

🔨 The type Class – The Default Metaclass

Normally, we create classes using the class keyword:

class FoodType(object):
    def __init__(self, ftype):
        self.ftype = ftype

    def getFtype(self):
        return self.ftype

fType = FoodType(ftype='Vegetarian')
print(fType.getFtype())

Output:

Vegetarian

But internally, Python uses the built-in type class to do the same thing:

def init(self, ftype):
    self.ftype = ftype

def getFtype(self):
    return self.ftype

FoodType = type('FoodType', (object,), {
    '__init__': init,
    'getFtype': getFtype
})

fType = FoodType(ftype='Vegetarian')
print(fType.getFtype())

Output:

Vegetarian

Here’s how the type arguments work:

  1. First argument: the class name (string).

  2. Second argument: tuple of base classes (for inheritance).

  3. Third argument: dictionary of attributes and methods.

🧬 Creating Subclasses with type

We can also use type to create subclasses dynamically.

Normal way using class:

class FoodType(object):
    def __init__(self, ftype):
        self.ftype = ftype

    def getFtype(self):
        return self.ftype

class VegType(FoodType):
    def vegFoods(self):
        return {'Spinach', 'Bitter Gourd'}

vType = VegType(ftype='Vegetarian')
print(vType.getFtype())
print(vType.vegFoods())

Dynamic way using type:

def init(self, ftype):
    self.ftype = ftype

def getFtype(self):
    return self.ftype

FoodType = type('FoodType', (object,), {
    '__init__': init,
    'getFtype': getFtype
})

def vegFoods(self):
    return {'Spinach', 'Bitter Gourd'}

VegType = type('VegType', (FoodType,), {
    'vegFoods': vegFoods
})

vType = VegType(ftype='Vegetarian')
print(vType.getFtype())
print(vType.vegFoods())

⚙️ Writing Custom Metaclasses

Metaclasses are created by inheriting from type and customizing the __new__ method.

class MetaCls(type):
    def __new__(cls, clsname, superclasses, attrs):
        print("Creating class:", clsname)
        return super().__new__(cls, clsname, superclasses, attrs)

C = MetaCls('C', (object,), {})
print(type(C))

Output:

Creating class: C
<class '__main__.MetaCls'>

Here, the class C was created by MetaCls instead of the default type.

🏗️ Metaclass Inheritance

When a class is built using a metaclass, its subclasses also inherit that metaclass unless specified otherwise. However, Python does not allow a single class to be created from two conflicting metaclasses — it raises a TypeError because a class can only have one metaclass.

🛠️ Use Cases of Metaclasses

Metaclasses are rarely needed in day-to-day programming, but they become valuable in special cases.

1. âś… Class Verification

They can enforce that a class must follow certain rules:

class MainClass(type):
    def __new__(cls, name, bases, attrs):
        if 'foo' not in attrs and 'bar' not in attrs:
            raise TypeError(f"Class {name} must define foo or bar")
        return super().__new__(cls, name, bases, attrs)

class SubClass(metaclass=MainClass):
    foo = 42

2. đźš« Preventing Attribute Inheritance

Useful for abstract classes to ensure subclasses don’t inherit unwanted methods.

3. ⚡ Dynamic Class Generation

They allow dynamic creation of classes at runtime — helpful in frameworks and plugins.

🔍 Key Points About Metaclasses

  • Classes create objects, and metaclasses create classes.

  • Python’s default metaclass is type.

  • You can write custom metaclasses by inheriting from type.

  • They’re useful for validation, enforcing rules, and dynamic class generation.

📌 Summary

Metaclasses in Python are essentially blueprints for classes. While every class by default is created using the type metaclass, you can define your own to control how classes are built. They are advanced tools that make sense in frameworks, code validation, and dynamic class creation. In short: objects come from classes, and classes come from metaclasses. 🚀