Fundamentals 6 min read

Understanding Python Metaclasses: Objects, Types, and Custom Class Creation

This article explains Python’s object model, showing that everything—including classes—is an object, describing how the built‑in type function serves as a metaclass, and demonstrating custom metaclass creation and practical examples such as subclass tracking and final class enforcement.

Qunar Tech Salon
Qunar Tech Salon
Qunar Tech Salon
Understanding Python Metaclasses: Objects, Types, and Custom Class Creation

Python treats everything as an object, including classes themselves, which are instances of the built‑in type metaclass. The article begins by illustrating that simple objects and class objects share the same type representation.

class MyClass:
    pass

a = int("5")
 b = MyClass()
print(type(a))
print(type(b))

Since classes are objects, they also have a type:

class MyClass:
    pass
print(type(MyClass))

Calling type with a name, bases tuple, and attribute dictionary creates a new class dynamically:

MyClass = type("MyClass", (), {})
instance = MyClass()
print(type(instance))

When a class inherits from another, Python internally translates it to a type call with the base class included:

class MyClass(int):
    name = "MyClass"
# Internally equivalent to:
# MyClass = type("MyClass", (int,), {"name": "MyClass"})

Custom metaclasses can be supplied via the metaclass keyword (Python 3) or the __metaclass__ attribute (Python 2):

# Python 3
class MyClass(metaclass=MetaClass):
    pass

# Python 2
class MyClass():
    __metaclass__ = MetaClass

A callable object that accepts name , bases , and attrs can serve as a metaclass. The article shows a simple function‑based metaclass:

def func_metaclass(name, bases, attrs):
    attrs["is_meta"] = True
    return type(name, bases, attrs)

class MyClass(metaclass=func_metaclass):
    pass

Defining a full metaclass class allows adding custom behavior during class creation, such as setting a flag:

class MetaClass(type):
    def __init__(cls, name, bases, attrs):
        super().__init__(name, bases, attrs)
        cls.is_meta = True

class MyClass(metaclass=MetaClass):
    pass

print(MyClass.is_meta)

Practical use‑cases include tracking subclass creation by overriding __init__ in a metaclass:

class TrackSubclasses(type):
    subclasses = {}
    def __init__(cls, name, bases, attrs):
        for base in bases:
            cls.subclasses[base] = cls.subclasses.get(base, 0) + 1
        super().__init__(name, bases, attrs)

class A(metaclass=TrackSubclasses):
    pass
class B(A):
    pass
class C(A):
    pass
class D(B):
    pass

print(TrackSubclasses.subclasses)

Another example demonstrates a "final" metaclass that prevents further subclassing:

class Final(type):
    def __init__(cls, name, bases, attrs):
        super().__init__(name, bases, attrs)
        for klass in bases:
            if isinstance(klass, Final):
                raise TypeError(f"{klass.__name__} is final")

class FinalClass(metaclass=Final):
    pass

class ChildClass(FinalClass):
    pass

Overall, the article clarifies that in Python, type is the default metaclass for all classes, but developers can define and use custom metaclasses to control class creation, enforce constraints, or inject additional behavior.

Pythonobject-orientedtypemetaclasscustom class creation
Qunar Tech Salon
Written by

Qunar Tech Salon

Qunar Tech Salon is a learning and exchange platform for Qunar engineers and industry peers. We share cutting-edge technology trends and topics, providing a free platform for mid-to-senior technical professionals to exchange and learn.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.