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.
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__ = MetaClassA 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):
passDefining 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):
passOverall, 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.
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.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.