python-3.x - 获取 ABCMeta 的所有注册子类

标签 python-3.x subclass abstract-base-class

我有一个类似于下面的目录结构:

.
├── main.py
├── model.py
└── models
    ├── __init__.py
    ├── model_a.py
    └── model_b.py

model.py 包含一个抽象基类:

from abc import ABCMeta, abstractmethod

class Base(metaclass=ABCMeta):

    @abstractmethod
    def run(self):
        pass

models 文件夹中是这个基类的两个实现,model_a.pymodel_b.py,它们将自己注册到 main 类。 model_a.py 看起来像这样:

from model import Base

class ModelA(Base):

    def run(self):
        return "a"

ModelA.register(Base)

assert issubclass(ModelA, Base)

model_b.py类似。

现在,我在 main.py 中尝试做的是创建 Base 的所有子类的字典,以便我可以选择一个(通过 GUI我的程序)并运行它:

from model import Base

subclasses = Base.__subclasses__()

dct = {cls.__name__: cls for cls in subclasses}

klass = dct['ModelA']
klass.run()

但我无法让它工作。当我尝试执行其中一个派生类并且 main.py 中的字典为空时,我得到了 RuntimeError: Refusing to create an inheritance cycle

最佳答案

我意识到这已经很晚了,但万一它对其他偶然发现这个的人有帮助......

这里有一些问题:

  1. 你的类(class)是错误的register称呼;只有在这种情况下调用 Base.register(ModelA) 才有意义(不是反过来)为了注册ModelA作为 Base 的“virtual subclass” .

  2. 调用 ModelA.register(Base)正在尝试注册 Base作为 ModelA 的虚拟子类,但是 ModelA已经是 Base 的实际子类, - 这就是您获得继承周期的原因。您不能让类 X 和 Y 相互继承。

  3. 然而,作为ModelA明确是 Base 的子类, 你不需要打电话 register根本。您想要:

    class ModelA(Base):
       ...
    

    没有 register调用(此处 ModelABase 的实际子类),或者:

    class ModelA:
        ...
    
    Base.register(ModelA)
    

    (此处 ModelA 是一个独立的类,在 Base 的继承层次之外,但它被注册为一个虚拟子类)。要么/要么 - 不能两者兼而有之。

    无论哪种情况,issubclass(ModelA, Base)将是 True .

  4. __subclasses__()不选择虚拟子类,只有实际的子类 - 所以如果你想使用它,你应该忘记 register()然后制作ModelA Base 的真正子类(上面的第一个选项)。

    (在我看来,这是整个 ABC/register 机制的缺陷:issubclass() 可能是 True__subclasses__() 没有捡起来 - 讨厌。)

  5. 如果您不导入包含ModelA 的模型在你执行的某些点,它从来没有设置所以ModelA不会出现在 Base.__subclassess__() 中反正。这可能就是为什么字典在 main.py是空的。

    解决方法是在 main.py 中添加一行说import models , 并有 models/__init__.py进口 model_amodel_b .然后当main运行,它导入 models , 又进口 model_amodel_a , 执行 ModelA 的定义和 ModelB并将它们添加到 Base的类层次结构。

  6. 在最后一行,您没有实例化任何类的实例 klass指着;该行应该是:

    klass().run()
    

关于python-3.x - 获取 ABCMeta 的所有注册子类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51306462/

相关文章:

python - 使用 pip install 安装语言检查时出错

objective-c - iOS - touchesMoved 在子类 UIScrollView 中只调用一次

c# - 如何将一个 "clone"对象转化为子类对象?

swift - 从未出现在 View 中的子类创建按钮

python - Python 抽象基类可以强制执行函数签名吗?

c++ - 以自身为参数的抽象基类虚纯方法

c++ - 指向基类的指针在 while 循环中丢失,导致段错误。 C++

python-3.x - 从 xlsxwriter 生成的 excel 图表中隐藏 #N/A 或空单元格

python - Tkinter.tclerror : no display name and no $display environment variable Ubuntu 20. 04

python - 如何在 postgresql 中进行分页?