Is it possible to dynamically create a metaclass for a class with several bases, in Python 3?
<p>In Python 2, with a trick it is possible to create a class with several bases, although the bases have metaclasses that are <em>not</em> subclass of each other.</p>

<p>The trick is that these metaclasses have themselves a metaclass (name it a "metametaclass"), and this metametaclass provides the metaclasses with a call method that dynamically creates a common sub-metaclass of the base metaclasses, if necessary. Eventually, a class results whose metaclass is the new sub-metaclass. Here is the code:</p>

<pre><code>&gt;&gt;&gt; class MetaMeta(type):
...     def __call__(mcls, name, bases, methods):
...         metabases = set(type(X) for X in bases)
...         metabases.add(mcls)
...         if len(metabases) &gt; 1:
...             mcls = type(''.join([X.__name__ for X in metabases]), tuple(metabases), {})
...         return mcls.__new__(mcls, name, bases, methods)
... 
&gt;&gt;&gt; class Meta1(type):
...     __metaclass__ = MetaMeta
... 
&gt;&gt;&gt; class Meta2(type):
...     __metaclass__ = MetaMeta
... 
&gt;&gt;&gt; class C1:
...     __metaclass__ = Meta1
... 
&gt;&gt;&gt; class C2:
...     __metaclass__ = Meta2
... 
&gt;&gt;&gt; type(C1)
&lt;class '__main__.Meta1'&gt;
&gt;&gt;&gt; type(C2)
&lt;class '__main__.Meta2'&gt;
&gt;&gt;&gt; class C3(C1,C2): pass
... 
&gt;&gt;&gt; type(C3)
&lt;class '__main__.Meta1Meta2'&gt;
</code></pre>

<p>This example (of course changing the syntax to <code>class C1(metaclass=Meta1)</code> etc) doesn't work in Python 3.</p>

<p><strong>Question 1:</strong> Do I understand correctly that in Python 2, first <code>C3</code> is constructed, using the metaclass of the first base, and an error would only result if <code>type(C3)</code> were not a common subclass of <code>type(C1)</code> and <code>type(C2)</code>, whereas in Python 3 the error is raised earlier?</p>

<p><strong>Question 2:</strong> (How) Is it possible to make the above example work in Python 3? I did try to use a subclass of <code>abc.ABCMeta</code> as metametaclass, but even though using a custom <code>__subclasscheck__</code> makes <code>issubclass(Meta1, Meta2)</code> return <code>True</code>, the creation of C3 would still result in an error.</p>

<p><strong>Note:</strong> Of course I could make Python 3 happy by statically defining <code>Meta1Meta2</code> and explicitly using it as a metaclass for <code>C3</code>. However, that's not what I want. I want that the common sub-metaclass is created dynamically.</p>

<p>In Python3  at the time the metaclass is used it have to be ready, and it can't  know about the bases of the final (non-meta) class in order to dynamically create a metaclass at that point. </p>

<p>But ynstead of complicating things (I confess I could not wrap my head around your need for a meta-meta-class) - you can simply use normal class hierarchy with collaborative use of <code>super</code> for your metaclasses.
You can even build the final metaclass dynamically with a simple
call to <code>type</code>: </p>

<pre><code>class A(type):
    def __new__(metacls, name, bases,attrs):
        attrs['A'] = "Metaclass A processed"
        return super().__new__(metacls, name, bases,attrs)


class B(type):
    def __new__(metacls, name, bases,attrs):
        attrs['B'] = "Metaclass A processed"
        return super().__new__(metacls, name, bases,attrs)


C = type("C", (A, B), {})

class Example(metaclass=C): pass
</code></pre>

<p>And:</p>

<pre><code>In[47] :Example.A
Out[47]: 'Metaclass A processed'

In[48]: Example.B
Out[48]: 'Metaclass A processed'
</code></pre>

<p>If your metaclasses are not designed to be collaborative in the first place, it will be very tricky to create any automatic method to combine them - and it would possibly involve monkey-patching the call to <code>type.__new__</code> in some of the metaclasses constructors. </p>

<p>As for not needing to explictly build <code>C</code>, you can use a normal function as the metaclass parameter, that will inspect the bases and build a dynamic derived metaclass. :</p>

<pre><code>def Auto(name, bases, attrs):
    basemetaclasses = []
    for base in bases:
        metacls = type(base)
        if isinstance(metacls, type) and metacls is not type and not metacls in basemetaclasses:
            basemetaclasses.append(metacls)
    dynamic = type(''.join(b.__name__ for b in basemetaclasses), tuple(basemetaclasses), {})
    return dynamic(name, bases, attrs)
</code></pre>

<p>(This code is very similar to yours - but I used a three-line explicit <code>for</code> instead of a <code>set</code> in order to preserve the metaclass order - which might matter)</p>

<p>You have them to pass Auto as an metaclass for derived classes, but otherwise it works as in your example:</p>

<pre><code>In [61]: class AA(metaclass=A):pass

In [62]: class BB(metaclass=B):pass

In [63]: class CC(AA,BB): pass
---------------------------------------------------------------------------
...
TypeError:   metaclass conflict
...

In [66]: class CC(AA,BB, metaclass=Auto): pass

In [67]: type(CC)
Out[67]: __main__.AB

In [68]: CC.A
Out[68]: 'Metaclass A processed'
</code></pre>

python metaclass