Metaclass Mixin or Chaining?

I don't think you can chain them like that, and I don't know how that would work either.

But you can make new metaclasses during runtime and use them. But that's a horrid hack. :)

zope.interface does something similar, it has an advisor metaclass, that will just do some things to the class after construction. If there was a metclass already, one of the things it will do it set that previous metaclass as the metaclass once it's finished.

(However, avoid doing these kinds of things unless you have to, or think it's fun.)


A type can have only one metaclass, because a metaclass simply states what the class statement does - having more than one would make no sense. For the same reason "chaining" makes no sense: the first metaclass creates the type, so what is the 2nd supposed to do?

You will have to merge the two metaclasses (just like with any other class). But that can be tricky, especially if you don't really know what they do.

class MyModelBase(type):
    def __new__(cls, name, bases, attr):
        attr['MyModelBase'] = 'was here'
        return type.__new__(cls,name, bases, attr)

class MyMixin(type):
    def __new__(cls, name, bases, attr):
        attr['MyMixin'] = 'was here'
        return type.__new__(cls, name, bases, attr)

class ChainedMeta(MyModelBase, MyMixin):
    def __init__(cls, name, bases, attr):
        # call both parents
        MyModelBase.__init__(cls,name, bases, attr)
        MyMixin.__init__(cls,name, bases, attr)

    def __new__(cls, name, bases, attr):
        # so, how is the new type supposed to look?
        # maybe create the first
        t1 = MyModelBase.__new__(cls, name, bases, attr)
        # and pass it's data on to the next?
        name = t1.__name__
        bases = tuple(t1.mro())
        attr = t1.__dict__.copy()
        t2 = MyMixin.__new__(cls, name, bases, attr)
        return t2

class Model(object):
    __metaclass__ = MyModelBase # inherits from `ModelBase`

class MyModel(Model):
    __metaclass__ = ChainedMeta

print MyModel.MyModelBase
print MyModel.MyMixin

As you can see this is involves some guesswork already, since you don't really know what the other metaclasses do. If both metaclasses are really simple this might work, but I wouldn't have too much confidence in a solution like this.

Writing a metaclass for metaclasses that merges multiple bases is left as an exercise to the reader ;-P


I don't know any way to "mix" metaclasses, but you can inherit and override them just like you would normal classes.

Say I've got a BaseModel:

class BaseModel(object):
    __metaclass__ = Blah

and you now you want to inherit this in a new class called MyModel, but you want to insert some additional functionality into the metaclass, but otherwise leave the original functionality intact. To do that, you'd do something like:

class MyModelMetaClass(BaseModel.__metaclass__):
    def __init__(cls, *args, **kwargs):
        do_custom_stuff()
        super(MyModelMetaClass, cls).__init__(*args, **kwargs)
        do_more_custom_stuff()

class MyModel(BaseModel):
    __metaclass__ = MyModelMetaClass