我有一个类似于下面的目录结构:
.
├── 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.py
和 model_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
。
最佳答案
我意识到这已经很晚了,但万一它对其他偶然发现这个的人有帮助......
这里有一些问题:
你的类(class)是错误的
register
称呼;只有在这种情况下调用Base.register(ModelA)
才有意义(不是反过来)为了注册ModelA
作为Base
的“virtual subclass” .调用
ModelA.register(Base)
正在尝试注册Base
作为ModelA
的虚拟子类,但是ModelA
已经是Base
的实际子类, - 这就是您获得继承周期的原因。您不能让类 X 和 Y 相互继承。然而,作为
ModelA
明确是Base
的子类, 你不需要打电话register
根本。您想要:class ModelA(Base): ...
没有
register
调用(此处ModelA
是Base
的实际子类),或者:class ModelA: ... Base.register(ModelA)
(此处
ModelA
是一个独立的类,在Base
的继承层次之外,但它被注册为一个虚拟子类)。要么/要么 - 不能两者兼而有之。无论哪种情况,
issubclass(ModelA, Base)
将是True
.__subclasses__()
不选择虚拟子类,只有实际的子类 - 所以如果你想使用它,你应该忘记register()
然后制作ModelA
Base
的真正子类(上面的第一个选项)。(在我看来,这是整个 ABC/
register
机制的缺陷:issubclass()
可能是True
但__subclasses__()
没有捡起来 - 讨厌。)如果您不导入包含
ModelA
的模型在你执行的某些点,它从来没有设置所以ModelA
不会出现在Base.__subclassess__()
中反正。这可能就是为什么字典在main.py
是空的。解决方法是在
main.py
中添加一行说import models
, 并有models/__init__.py
进口model_a
和model_b
.然后当main
运行,它导入models
, 又进口model_a
和model_a
, 执行ModelA
的定义和ModelB
并将它们添加到Base
的类层次结构。在最后一行,您没有实例化任何类的实例
klass
指着;该行应该是:klass().run()
关于python-3.x - 获取 ABCMeta 的所有注册子类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51306462/