我有一个class1,需要继承2个不同的元类,即Meta1和abc.ABCMeta

当前实现:

Meta1的实现:

class Meta1(type):
    def __new__(cls, classname, parent, attr):
        new_class = type.__new__(cls, classname, parent, attr)
        return super(Meta1, cls).__new__(cls, classname, parent, attr)

class1Abstract的实现
class class1Abstract(object):
    __metaclass__ = Meta1
    __metaclass__ = abc.ABCMeta

主类的实现
class mainClass(class1Abstract):
    # do abstract method stuff

我知道两次实现2个不同的meta是错误的。

我改变了metclass的加载方式(尝试了几次),我得到了
TypeError:调用元类基础时出错
metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases

我没主意了...
EDITED 1
我尝试了此解决方案,但它有效,但mainClass不是class1Abstract的实例
print issubclass(mainClass, class1Abstract) # true
print isinstance(mainClass, class1Abstract) # false

class1Abstract的实现
class TestMeta(Meta1):
    pass


class AbcMeta(object):
    __metaclass__ = abc.ABCMeta
    pass


class CombineMeta(AbcMeta, TestMeta):
    pass


class class1Abstract(object):
    __metaclass__ = CombineMeta

    @abc.abstractmethod
    def do_shared_stuff(self):
        pass

    @abc.abstractmethod
    def test_method(self):
        ''' test method '''

mainClass的实现
class mainClass(class1Abstract):
    def do_shared_stuff(self):
        print issubclass(mainClass, class1Abstract) # True
        print isinstance(mainClass, class1Abstract) # False

由于mainClass继承自抽象类,因此python应该抱怨test_method没有在mainClass中实现。但是它没有任何抱怨,因为print isinstance(mainClass,class1Abstract)#False
dir(mainClass)没有
['__abstractmethods__', '_abc_cache', '_abc_negative_cache', '_abc_negative_cache_version', '_abc_registry']

救命!
EDITED 2
class1Abstract的实现
CombineMeta = type("CombineMeta", (abc.ABCMeta, Meta1), {})
class class1Abstract(object):
    __metaclass__ = abc.ABCMeta

    @abc.abstractmethod
    def do_shared_stuff(self):
        pass

    @abc.abstractmethod
    def test_method(self):
        ''' test method '''

mainClass的实现
class mainClass(class1Abstract):
    __metaclass__ = CombineMeta
    def do_shared_stuff(self):
        print issubclass(mainClass, class1Abstract) # True
        print isinstance(mainClass, class1Abstract) # False
dir(mainClass)现在具有abstractmethod的魔术方法
['__abstractmethods__', '__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__metaclass__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_abc_cache', '_abc_negative_cache', '_abc_negative_cache_version', '_abc_registry', 'do_shared_stuff', 'test_method']

但是python不会警告test_method不会被实例化

救命!

最佳答案

默认情况下,python只会在尝试实例化类时抱怨类具有抽象方法,而不是在创建类时抱怨。这是因为该类的元类仍为ABCMeta(或其子类型),因此允许使用抽象方法。

要获得所需的内容,您需要编写自己的元类,当它发现__abstractmethods__不为空时会引发错误。这样,您必须明确声明何时不再允许类使用抽象方法。

from abc import ABCMeta, abstractmethod

class YourMeta(type):
    def __init__(self, *args, **kwargs):
        super(YourMeta, self).__init__(*args, **kwargs)
        print "YourMeta.__init__"
    def __new__(cls, *args, **kwargs):
        newcls = super(YourMeta, cls).__new__(cls, *args, **kwargs)
        print "YourMeta.__new__"
        return newcls

class ConcreteClassMeta(ABCMeta):
    def __init__(self, *args, **kwargs):
        super(ConcreteClassMeta, self).__init__(*args, **kwargs)
        if self.__abstractmethods__:
            raise TypeError("{} has not implemented abstract methods {}".format(
                self.__name__, ", ".join(self.__abstractmethods__)))

class CombinedMeta(ConcreteClassMeta, YourMeta):
    pass

class AbstractBase(object):
    __metaclass__ = ABCMeta

    @abstractmethod
    def f(self):
        raise NotImplemented

try:
    class ConcreteClass(AbstractBase):
        __metaclass__ = CombinedMeta

except TypeError as e:
    print "Couldn't create class --", e

class ConcreteClass(AbstractBase):
    __metaclass__ = CombinedMeta
    def f(self):
        print "ConcreteClass.f"

assert hasattr(ConcreteClass, "__abstractmethods__")
c = ConcreteClass()
c.f()

哪个输出:
YourMeta.__new__
YourMeta.__init__
Couldn't create class -- ConcreteClass has not implemented abstract methods f
YourMeta.__new__
YourMeta.__init__
ConcreteClass.f

关于python - 1个类继承2个不同的元类(abcmeta和用户定义的元),我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/31379485/

10-11 19:19