Advanced⏱ 20 min

Metaclasses

If a class is a blueprint for objects, a metaclass is a blueprint for classes. This is as deep as Python goes — but understanding it unlocks how frameworks like Django and SQLAlchemy work their magic.

Everything in Python is an Object

Classes themselves are objects — instances of type. type is the default metaclass. When Python sees class Foo:, it calls type("Foo", bases, namespace) to create it.

python
class Dog:
    species = "Canis familiaris"
    def bark(self): return "Woof!"

# Dog itself is an object
print(type(Dog))          # <class 'type'>
print(type(42))           # <class 'int'>
print(type("hi"))         # <class 'str'>

# type() can CREATE classes dynamically
Cat = type("Cat", (), {
    "sound": "Meow",
    "speak": lambda self: self.sound
})

cat = Cat()
print(type(Cat))          # <class 'type'>
print(cat.speak())        # Meow

# Check the MRO (method resolution order)
class A: pass
class B(A): pass
class C(B): pass
print(C.__mro__)   # (C, B, A, object)
Output

Creating a Metaclass

Subclass type, override __new__ or __init__, and use it via metaclass=. This lets you intercept and modify class creation.

python
class UpperAttrMeta(type):
    """Metaclass that converts all attribute names to UPPERCASE."""
    def __new__(mcs, name, bases, namespace):
        upper_ns = {
            k.upper() if not k.startswith("_") else k: v
            for k, v in namespace.items()
        }
        return super().__new__(mcs, name, bases, upper_ns)

class MyClass(metaclass=UpperAttrMeta):
    greeting = "hello"
    value    = 42

    def say(self):
        return "speaking"

obj = MyClass()
print(obj.GREETING)   # hello   (attribute was uppercased!)
print(obj.VALUE)      # 42
print(obj.SAY())      # speaking

# This is how ORM libraries like SQLAlchemy work:
# you write normal class attributes, the metaclass
# transforms them into database column definitions
Output

Practical: Singleton Pattern via Metaclass

python
class SingletonMeta(type):
    """Ensures only one instance of a class ever exists."""
    _instances = {}

    def __call__(cls, *args, **kwargs):
        if cls not in cls._instances:
            cls._instances[cls] = super().__call__(*args, **kwargs)
        return cls._instances[cls]

class DatabaseConnection(metaclass=SingletonMeta):
    def __init__(self, url):
        self.url = url
        print(f"Connecting to {url}...")

    def query(self, sql):
        return f"Results for: {sql}"

# First call creates the instance
db1 = DatabaseConnection("postgresql://localhost/mydb")
db2 = DatabaseConnection("postgresql://localhost/other")   # reuses existing!

print(db1 is db2)       # True — same object
print(db1.url)          # postgresql://localhost/mydb
print(db2.url)          # same — no second connection made
Output
💡
When should you use metaclasses?Almost never in application code. But knowing how they work explains Flask's @app.route, Django's Model, SQLAlchemy's column definitions — all use metaclasses (or similar __init_subclass__ hooks) under the hood.
🏆

You've completed Python Experiments!

You now understand Python from variables all the way to metaclasses — that's the 0→90% journey. See your progress →

🏆

Certificate Unlocked!

You completed all lessons with 70%+. View your certificate →