Python中的ABC多重继承

19

我认为代码会比我用语言更好地解释问题。这是在我的_abc.py中的代码:

from abc import ABCMeta, abstractmethod

class MyABC(object):
    __metaclass__ = ABCMeta

    @abstractmethod
    def print(self):
        pass

这是我在my_class.py中的代码

from my_abc import MyABC
from third_party_package import SomeClass

class MyClass(MyABC, SomeClass):
    def __init__(self):
        super(MyClass, self).__init__()

    def print(self):
        print('Hello ABC')

当我尝试运行my_class.py时,出现以下错误:

TypeError: 调用元类基类时出错:元类冲突:派生类的元类必须是其所有基类的元类的(非严格)子类

我理解可以创建一个直接从我的接口MyABC继承的类,然后创建另一个类同时继承我创建的这个类和第三方模块的类。

我的问题是:是否有其他更好、更适当的方法可以直接完成此操作,而无需为此创建中间类?


1
你提出的解决方法真的有效吗?如果在MyABCMyClass之间加入另一个类,我会预期你会遇到完全相同的问题。问题在于SomeClass具有不同且不兼容的元类。如果不知道它是什么,我不确定是否有任何回答这个问题的方法。你能添加一些关于SomeClass的具体细节吗? - Blckknght
我正在使用一个名为urwid的第三方库。它是Python的ncurses替代品,具有更清晰的API。根据我上面提供的示例,SomeClass对应于urwid.ListBox类,这是一种用于创建类似列表框的UI组件的小部件。我不确定如何找到urwid.ListBox的元类,但当我使用上面的代码运行它时,我会得到相同的TypeError错误。 - moeabdol
1
尝试创建一个中间元类:class MyMeta(ABCMeta, type(SomeClass)): pass,然后将其用作 MyClass__metaclass__ - user4815162342
3个回答

11

SomeClass类有一个自定义元类。您需要创建一个继承自ABCMeta和这个自定义元类的元类,然后将其用作MyClass的元类。在不了解更多关于此自定义元类的信息的情况下,我无法确定在一般情况下正确的方法,但可能看起来像以下其中一种可能性:

class DerivedMeta(ABCMeta, type(SomeClass)):
    pass

class DerivedMeta(type(SomeClass), ABCMeta):
    pass

虽然不太可能,但有可能您还需要覆盖一个或多个方法来确保正确的元类交互。


1
@moeabdol:在这篇文章中有一些讨论,但它也谈到了很多其他的东西。 - Kevin
对于不了解元类的人,我在stackoverflow上找到了一个很好的解释,请查看e-satis在这里的答案https://dev59.com/WnVD5IYBdhLWcg3wE3Ro,谢谢stackoverflow。 - moeabdol

6

线程仍然在搜索结果的顶部,所以我想分享我的完整解决方案。
我在尝试创建一个用于PyQt5小部件的抽象模板类时遇到了这个问题,在Python 3.8中应用了@Kevin的解决方案,首先创建了一个新的元类。以下是可工作的代码:

from abc import ABC, ABCMeta
from PyQt5.QtWidgets import QWidget, QLabel


class QABCMeta(ABCMeta, type(QWidget)):
    """Create a meta class that combines ABC and the Qt meta class"""
    pass


class TcWidget(ABC, metaclass=QABCMeta):
    """Abstract class, to be multi-inherited together with a Qt item"""
    pass


class TcLabel(QLabel, TcWidget):
    """Label that shows a value"""
    pass


# ...
label = TcLabel()
# ...

0

你也可以将另一个类的元类设置为 ABCMeta,以便所有多个基类的元类都是 ABCMeta。

当使用多重继承时,我遇到了类似的问题:

  • 一个类具有自定义元类
  • 一个类具有 ABCMeta 作为元类

我解决这个问题的方法是让我的自定义元类派生自 ABCMeta。这似乎在所有情况下都有效。

这对我在所有情况下都有效。

class MyMeta(ABCMeta):
  pass

取代

class MyMeta(type):
  pass

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接