【问题标题】:Python ABC Multiple InheritancePython ABC 多重继承
【发布时间】:2015-05-02 04:09:22
【问题描述】:

我认为代码比我用文字更能解释问题。这是 my_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 继承的类,然后创建另一个类,然后从我创建的这个类和我的第三方模块类继承。

我的问题是:是否有另一种更好、更合适的方式直接执行此操作,而无需为我的目的创建中间类?

【问题讨论】:

  • 您建议的解决方法是否真的有效?如果您在MyABCMyClass 之间放置另一个类,我希望您会遇到完全相同的问题。问题是SomeClass 具有不同且不兼容的元类。在不知道那是什么的情况下,我不确定是否有任何方法可以回答这个问题。你能补充一些关于SomeClass的具体细节吗?
  • 我正在使用一个名为 urwid 的第三方库。它是 python 的 ncurses 替代品,具有更清洁的 API。根据我上面提供的示例, SomeClass 对应于 urwid.ListBox 类,它是用于创建类似 UI 组件的列表框的小部件。我不确定如何找出 urwid.ListBox 的元类,但是当我使用上面的代码运行它时,我得到了相同的 TypeError。
  • 尝试创建一个中间元类:class MyMeta(ABCMeta, type(SomeClass)): pass,然后将其用作__metaclass__MyClass

标签: python python-2.7 multiple-inheritance metaclass urwid


【解决方案1】:

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

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

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

这不太可能,但您可能还需要重写一个或多个方法以确保正确的元类交互。

【讨论】:

  • @moeabdol:this essay 有一些讨论,但它也谈到了很多其他的东西。
  • 对于不知情的人,我在stackoverflow checkout e-satis's answer here中找到了元类的一个很好的解释stackoverflow.com/questions/100003/…谢谢stackoverflow
【解决方案2】:

话题仍然在搜索结果的顶部,所以我想分享我的完整解决方案。
我在尝试在 Python 3.8 中创建一个用于 PyQt5 小部件的抽象模板类时遇到了这个问题。我应用了@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()
# ...

【讨论】:

    【解决方案3】:

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

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

    • 具有自定义元类的类
    • 具有 ABCMeta 作为元类的类

    我为解决这个问题所做的就是让我的自定义元类派生自 ABCMeta。这似乎适用于所有情况。

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

    class MyMeta(ABCMeta):
      pass
    

    而不是

    class MyMeta(type):
      pass
    

    【讨论】:

      猜你喜欢
      • 2021-05-16
      • 2020-12-16
      • 2020-12-18
      • 2021-08-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-12-12
      • 2016-02-25
      相关资源
      最近更新 更多