Python 如何对元类使用多重继承?

Python 如何对元类使用多重继承?,python,flask,metaprogramming,flask-restful,Python,Flask,Metaprogramming,Flask Restful,我正在尝试使用注册表模式注册我用flaskrestful定义的所有资源 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._

我正在尝试使用注册表模式注册我用
flaskrestful
定义的所有资源

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()
当整个项目启动时,我得到以下信息:

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

我尝试了代理类的层,但结果仍然是一样的。那么,有没有办法使用此模式注册我的资源?

您的
DefaultResource
类似乎是从具有两个不同元类的类继承的:
BaseRegistered
(使用元类
ResourceRegistry
)和
Resource
(使用Flask的
MethodViewType
元类)

我建议你做一些类似的事情:

from flask.views import MethodViewType    

class CombinedType(ResourceRegistry, MethodViewType):
    pass

class BaseRegistered(object):
    __metaclass__ = Combinedtype

然后像以前一样继续。

元类是用来构建类的类,这意味着类的结构——例如,它的内部
\uuuuuuu dict\uuuuuu
,或者
\uuuuu getattribute\uuuuuu
提供的自动委托机制——都是由元类创建到类中的

当您从父类继承时,您是隐式继承其元类,因为您基本上只是扩展父类的结构,而父类的结构部分由其元类提供

因此,当你从一个类继承时,你要么保留你的父类给你的元类,要么定义一个从你的父类派生的新元类。在多重继承的情况下也是如此

下面是一个错误Python代码的示例

class ParentType(type):
    pass

class Parent(metaclass=ParentType):
    pass

class ChildType(type):
    pass

class Child(Parent, metaclass=ChildType):
    pass
这正是你在问题中提到的错误。使
ChildType
成为
ParentType
的子类可以解决这个问题

class ParentType(type):
    pass

class Parent(metaclass=ParentType):
    pass

class ChildType(ParentType):
    pass

class Child(Parent, metaclass=ChildType):
    pass
Dologan给出的答案正确地解决了创建一个元类的问题,该元类继承了这两个元类,然后直接使用它

然而,如果可能的话,我会避免这样一个复杂的解决方案。多重继承有点难管理——这不是一件坏事,只是很复杂——在元类中执行它可能会导致一些难以掌握的东西

这显然取决于您试图完成什么,以及您记录和测试解决方案的能力。如果您想要或需要使用元类解决它,我建议您利用抽象基类(基本上是类别)。abc在其
\u abc\u registry
属性中包含注册类的列表,但是没有官方方法获取它,最好避免直接使用它。但是,您可以派生ABCMeta并使其使用此代码保留公共注册表

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
现在,您可以使用
register()
方法创建仅从
RegistryABC
继承的类别:

class MyCategory(RegistryABC):
    pass

MyCategory.register(tuple)
MyCategory.register(str)

print(MyCategory.registry)

您在这里得到的是
[,]

它不需要太复杂,但您必须决定是否也应该在注册表中注册一些ResourceMixin(在这里它们会注册)。在Python2中,只需使用元类,我花了几个小时,因为我没有保存代码,我想知道这是什么魔法。 在我的例子中,我想添加额外的方法\u decorators,但资源类已经声明了它,所以不可能在attrs中添加它,而是在新的\u cls对象上设置。另外,不要忘记调用MethodViewType.\uuuuuuuuuuuuuuuuuu(super(),而不是type)


有益的指导
from flask_restful import Resource
from flask.views import MethodViewType

class ResourceRegistry(MethodViewType):

    REGISTRY = {}

    def __new__(cls, name, bases, attrs):
        new_cls = super().__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 DefaultResource(Resource, metaclass=ResourceRegistry):

    @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()