2016-03-22 9 views
2

Ich versuche, alle Ressourcen zu registrieren, die ich mit Flask-RESTFUL mit dem Registrierungsmuster definiert.Wie kann ich Mehrfachvererbung mit einer Metaklasse verwenden?

from flask_restful import Resource 

class ResourceRegistry(type): 

    REGISTRY = {} 

    def __new__(cls, name, bases, attrs): 
     new_cls = type.__new__(cls, name, bases, attrs) 
     cls.REGISTRY[new_cls.__name__] = new_cls 
     return new_cls 

    @classmethod 
    def get_registry(cls): 
     return dict(cls.REGISTRY) 


class BaseRegistered(object): 
    __metaclass__ = ResourceRegistry 


class DefaultResource(BaseRegistered, Resource): 

    @classmethod 
    def get_resource_name(cls): 
     s = re.sub('(.)([A-Z][a-z]+)', r'\1-\2', cls.__name__) 
     return '/' + re.sub('([a-z0-9])([A-Z])', r'\1-\2', s).lower() 

Wenn die ganze Sache gestartet ich folgendes:

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

Ich habe mit Schichten von Proxy-Klassen versucht, aber das Ergebnis ist immer noch das gleiche. Gibt es eine Möglichkeit, meine Ressourcen mit diesem Muster zu registrieren?

Antwort

3

Ihre DefaultResource Klasse scheint von Klassen mit zwei verschiedenen metaclasses zu vererben: BaseRegistered (mit metaclass ResourceRegistry) und Resource (mit Flasche der MethodViewType metaclass).

This answer würde vorschlagen, etwas zu tun:

from flask.views import MethodViewType  

class CombinedType(ResourceRegistry, MethodViewType): 
    pass 

class BaseRegistered(object): 
    __metaclass__ = Combinedtype 

Und dann wie zuvor fort.

2

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'>].

+0

Hilfreiche Anweisung – ChipJust