Python Meta Classes

Last Updated : 17 Feb, 2026

A metaclass in Python is a class that defines how other classes are created and behave. Just like objects are created from classes, classes themselves are created from metaclasses.

In short:

  • Class → creates objects
  • Metaclass → creates classes

By default, Python uses the built-in metaclass "type" to create all classes.

Steps to Create a Metaclass

  1. Define a metaclass: Create a class that inherits from type. Optionally, define __new__ or __init__ to customize class creation.
  2. Use the metaclass in a class: Specify metaclass=YourMeta when defining a class.
  3. Class is created by the metaclass: The metaclass can modify attributes or methods of the class automatically.
  4. Create instances of the class: Instances work normally, the metaclass only affects the class itself.
Python
class Meta(type):
    def __new__(cls, name, bases, dct):
        dct['greet'] = lambda self: f"Hello from {name}!"
        return super().__new__(cls, name, bases, dct)

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

p = Person("Olivia")

print(p.greet())  

Output
Hello from Person!

Explanation:

  • Meta(type): Defines a metaclass that can modify classes when they are created.
  • __new__: Adds a greet method automatically to any class using this metaclass.
  • Person(metaclass=Meta): Class created using the metaclass, so it gets the greet method.
  • p = Person("Olivia"): Creates an instance of Person.
  • p.greet(): Calls the method injected by the metaclass.

Creating Subclass

Subclasses can also be created dynamically using type.

Python
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 Guard'}

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

v = VegType("Vegetarian")
print(v.getFtype())
print(v.vegFoods())

Output
Vegetarian
{'Bitter Guard', 'Spinach'}

Explanation:

  • VegType inherits from FoodType dynamically.
  • vegFoods method is added via the attributes dictionary.

Metaclass Inheritance

Metaclasses can be inherited just like normal classes. When a class inherits from a metaclass, it becomes an instance of that metaclass.

Python
class MetaCls(type):
    pass

A = MetaCls('A', (object,), {})
class B(object):
    pass
class C(A, B):
    pass

print(type(A))  
print(type(B))  
print(type(C))  

Output
<class '__main__.MetaCls'>
<class 'type'>
<class '__main__.MetaCls'>

Explanation:

  • A is created by MetaCls -> type is MetaCls
  • B is normal -> type is type
  • C inherits from A -> type is MetaCls

Metaclass Conflicts

A class cannot inherit from two different metaclasses. Python will raise a TypeError.

Python
class MetaCls(type):
    pass

A = MetaCls('A', (object,), {})
print("Type of A:", type(A))

class B(object):
    pass
print("Type of B:", type(B))

class C(A, B):
    pass

print("Type of C:", type(C))

Error:

TypeError: metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases

Explanation:

  • Python allows only one metaclass per class.
  • 'C' inherits from two different metaclasses → conflict occurs.

Metaclass Use Cases

Metaclasses are useful when you want to control class creation or enforce rules.

1. Class Verification: This example shows how a metaclass can enforce rules on class attributes.

Python
class MainClass(type):
    def __new__(cls, name, bases, attrs):
        if 'foo' in attrs and 'bar' in attrs:
            raise TypeError(f"Class {name} cannot have both foo and bar")
        return super().__new__(cls, name, bases, attrs)

# This will raise an error
class SubClass(metaclass=MainClass):
    foo = 42
    bar = 34

Explanation:

  • Ensures a class cannot have both foo and bar attributes.
  • Useful for interface enforcement.

2. Prevent Subclass Inheritance: This example shows how a metaclass can treat abstract classes differently, preventing certain checks for them while enforcing rules on normal classes.

Python
class MetaCls(type):
    def __new__(cls, name, bases, attrs):
        if attrs.pop('abstract', False):
            print('Abstract Class:', name)
            return super().__new__(cls, name, bases, attrs)
        print('Normal Class:', name)
        return super().__new__(cls, name, bases, attrs)

class AbsCls(metaclass=MetaCls):
    abstract = True

class NormCls(metaclass=MetaCls):
    foo = 42

Output
Abstract Class: AbsCls
Normal Class: NormCls

Explanation:

  • Abstract classes can skip metaclass checks.
  • Normal classes are validated by the metaclass.

Dynamic Generation of Classes

Dynamic class generation allows you to create classes at runtime instead of defining them statically in code.

Python
class FoodType:
    events = []

    def __init__(self, ftype, items):
        self.ftype = ftype
        self.items = items
        FoodType.events.append(self)

    def run(self):
        print("Food Type:", self.ftype)
        print("Food Menu:", self.items)

    @staticmethod
    def run_events():
        for e in FoodType.events:
            e.run()

def sub_food(ftype):
    class_name = ftype.capitalize()
    def __init__(self, items):
        FoodType.__init__(self, ftype, items)
    globals()[class_name] = type(class_name, (FoodType,), {'__init__': __init__})

# Create dynamic classes
[ sub_food(ftype) for ftype in ["Vegetarian", "Nonvegetarian"] ]

Vegetarian(['Spinach', 'Bitter Guard'])
Nonvegetarian(['Meat', 'Fish'])
FoodType.run_events()

Output
Food Type: Vegetarian
Food Menu: ['Spinach', 'Bitter Guard']
Food Type: Nonvegetarian
Food Menu: ['Meat', 'Fish']

Explanation:

  • sub_food dynamically creates subclasses of FoodType.
  • Each subclass can be instantiated and used like normal classes.
Comment

Explore