2012-06-30 5 views
23

Ich muss eine Klasse erstellen, die abhängig von einer Bedingung eine andere Basisklasse verwendet. Bei einigen Klassen habe ich die berüchtigte:Python 3: TypeError: Metaklassenkonflikt: Die Metaklasse einer abgeleiteten Klasse muss eine (nicht strikte) Unterklasse der Metaklassen aller ihrer Basen sein.

TypeError: metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases 

Ein Beispiel sqlite3 ist, hier ist ein kurzes Beispiel, das Sie auch im Interpreter verwenden kann:

>>> import sqlite3 
>>> x = type('x', (sqlite3,), {}) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
TypeError: metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases 
>>> 

Wie kann ich dieses Problem lösen?

Danke.

+5

'sqlite3' ist ein Modul keine "Klasse". – agf

+0

@agf: Ich habe mir das nur angesehen und das Gleiche realisiert, als du das gepostet hast. – jdi

+0

Danke Agf, du hast Recht! sqlite3.Connection macht es funktioniert. –

Antwort

11

Obwohl Ihr Beispiel mit sqlite3 ungültig ist, weil es tatsächlich ein Modul und keine Klasse ist, habe ich das gleiche Problem festgestellt. Die Basisklasse hat eine Metaklasse eines anderen Typs als die Unterklasse, und dann sehen Sie diesen Fehler.

Ich endete mit einer Variation von this activestate snippet using noconflict.py. Dies ist leider nicht python 3.x kompatibel. Es gibt Ihnen die Idee, aber das Snippet müsste überarbeitet werden.

Problem Snippet

class M_A(type): 
    pass 
class M_B(type): 
    pass 
class A(object): 
    __metaclass__=M_A 
class B(object): 
    __metaclass__=M_B 
class C(A,B): 
    pass 

#Traceback (most recent call last): 
# File "<stdin>", line 1, in ? 
#TypeError: metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass #of the metaclasses of all its bases 

Lösung

from noconflict import classmaker 
class C(A,B): 
    __metaclass__=classmaker() 

print C 
#<class 'C'> 

Der Code Rezept löst richtig die Metaklassen für Sie Schnipsel.

+1

Python 3 verwendet die 'Klasse C (Metaklasse = MyMeta): 'Syntax – JBernardo

+0

@JBernardo: Danke. Ich habe bemerkt, dass es nicht py3 compat ist. Es hat ein paar andere Probleme im Snippet, die es nicht so gut funktionieren lassen. – jdi

+0

Sie könnten 'class C (six.with_metaclass (MyMeta))' verwenden, um es kompatibel mit python 3.x zu machen, oder? – Tgsmith61591

12

Statt die receipe der Verwendung, wie durch jdi erwähnt, können Sie direkt verwenden:

class M_C(M_A, M_B): 
    pass 

class C(A, B): 
    __metaclass__ = M_C 
6

das Muster von @ Michael beschrieben zu verwenden, aber sowohl mit Python 2 und 3 Kompatibilität (mit der six Bibliothek):

from six import with_metaclass 

class M_C(M_A, M_B): 
    pass 

class C(with_metaclass(M_C, A, B)): 
    # implement your class here 
1

Soweit ich aus den bisherigen Antworten verstanden die denken nur in der Regel tun, müssen wir manuell ist:

class M_A(type): pass 
class M_B(type): pass 
class A(metaclass=M_A): pass 
class B(metaclass=M_B): pass 

class M_C(M_A, M_B): pass 
class C:(A, B, metaclass=M_C): pass 

Aber wir können die letzten beiden Zeilen nun automatisieren:

def metaclass_resolver(*classes): 
    metaclass = tuple(set(type(cls) for cls in classes)) 
    metaclass = metaclass[0] if len(metaclass)==1 \ 
       else type("_".join(mcls.__name__ for mcls in metaclass), metaclass, {}) # class M_C 
    return metaclass("_".join(cls.__name__ for cls in classes), classes, {})    # class C 

class C(metaclass_resolver(A, B)): pass 

Da wir zwei beliebige Version spezifische metaclass Syntax diese metaclass_resolver Arbeiten mit Python nicht verwenden sowie Python 3.

Verwandte Themen