Paul's Programming Notes PostsRSSGithub

Python - "The Darker Side of type"

Most people know type() as the one-argument form that tells you an object’s type: type(1) returns <class 'int'>. Called with three arguments, it does something else entirely: it creates a new class at runtime.

type(name, bases, namespace) is equivalent to a class statement. These two produce the same class:

class Foo(object):
    pass

Foo = type('Foo', (object,), {})

The arguments are the class name, a tuple of base classes, and a dict of attributes and methods. A function put in that dict becomes a method on the class:

def always_false(self):
    return False

Foo = type('Foo', (object,), {'always_false': always_false})

You reach for this when you don’t know the classes you’ll need until runtime, so you can’t write them out ahead of time. The usual example is reflecting an unknown database schema and building a model class for each table on the fly.

I first ran into this in Jeff Knupp’s post “Improve Your Python: Metaclasses and Dynamic Classes With Type.” His blog is no longer up (archived copy). The three-argument type() is documented in the Python docs, and there’s a deeper walkthrough in Python 3 Patterns, Recipes and Idioms.