A Metaklasse ist die Klasse verwendet, um eine Klasse zu bauen, was bedeutet, dass die Struktur der Klasse - sein interne __dict__
, zum Beispiel, oder der automatische Delegationsmechanismus von __getattribute__
vorgesehen - wird in die Klasse durch die Metaklasse erstellt.
Wenn Sie von einer Elternklasse erben, erben Sie implizit seine Metaklasse, weil Sie im Grunde nur die Struktur der Elternklasse erweitern, die zum Teil von der Metaklasse bereitgestellt wird.
Wenn Sie also von einer Klasse erben, müssen Sie entweder die Metaklasse behalten, die Ihnen von Ihrem Elternteil gegeben wurde, oder eine neue Metaklasse definieren, die von der Ihrer Eltern abgeleitet ist. Dies gilt auch im Falle der Mehrfachvererbung.
Ein Beispiel für falschen Python-Code ist
class ParentType(type):
pass
class Parent(metaclass=ParentType):
pass
class ChildType(type):
pass
class Child(Parent, metaclass=ChildType):
pass
Dies gibt genau den Fehler, den Sie in Ihrer Frage erwähnen. Herstellung ChildType
eine Unterklasse von ParentType
der Ausgabe
class ParentType(type):
pass
class Parent(metaclass=ParentType):
pass
class ChildType(ParentType):
pass
class Child(Parent, metaclass=ChildType):
pass
Die von Dologan gegebenen Antwort löst adressiert das Problem richtig einen Metaklasse zu schaffen, die von erbt sowohl die metaclasses und es dann ohne weiteres verwendet werden.
Ich würde, wenn möglich, eine so komplexe Lösung jedoch vermeiden. Mehrfache Vererbung ist ein bisschen schwierig zu verwalten - nicht schlecht, nur komplex - und es in einer Metaklasse zu tun, könnte wirklich etwas schwer zu fassen führen.
Es hängt natürlich davon ab, was Sie erreichen möchten und wie gut Sie die Lösung dokumentieren und testen. Wenn Sie es mit Metaklassen lösen wollen oder müssen, würde ich vorschlagen, die abstrakten Basisklassen (die im Grunde Kategorien sind) zu nutzen. ABCs enthalten die Liste der registrierten Klassen in ihrem _abc_registry
Attribut, aber es gibt keine offizielle Methode, um sie zu erhalten, und es ist besser, sie direkt zu vermeiden.Sie können jedoch ABCMeta ableiten und es eine öffentliche Registrierung mit diesem Code
import abc
class RegistryABCMeta(abc.ABCMeta):
def __init__(self, name, bases, namespace):
super().__init__(name, bases, namespace)
self.registry = []
def register(self, subclass):
super().register(subclass)
self.registry.append(subclass)
class RegistryABC(metaclass=RegistryABCMeta):
pass
Sie Kategorien nur von RegistryABC
und mit Hilfe der register()
Methode erben erstellen können jetzt halten machen:
class MyCategory(RegistryABC):
pass
MyCategory.register(tuple)
MyCategory.register(str)
print(MyCategory.registry)
und was Sie hier bekommen, ist [<class 'tuple'>, <class 'str'>]
.
Hilfreiche Anweisung – ChipJust