获取 ABCMeta 的所有注册子类
Getting all registered subclasses of an ABCMeta
我的目录结构类似于以下内容:
.
├── main.py
├── model.py
└── models
├── __init__.py
├── model_a.py
└── model_b.py
model.py
包含一个抽象基础 Class:
from abc import ABCMeta, abstractmethod
class Base(metaclass=ABCMeta):
@abstractmethod
def run(self):
pass
在 models
文件夹中是此基础 class、model_a.py
和 model_b.py
的两个实现,它们将自己注册到主 Base
class。 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
的所有子 class 的字典,这样我就可以 select (通过我程序的 GUI)和 运行 它:
from model import Base
subclasses = Base.__subclasses__()
dct = {cls.__name__: cls for cls in subclasses}
klass = dct['ModelA']
klass.run()
但我无法让它工作。当我尝试执行派生的 classes 之一并且 main.py
中的字典为空时,我得到 RuntimeError: Refusing to create an inheritance cycle
。
我意识到这已经很晚了,但万一它对其他偶然发现这个的人有帮助...
你在这里遇到了一些问题:
你的 classes 在那个 register
调用中是错误的;只有在这种情况下调用 Base.register(ModelA)
(而不是相反)才有意义,以便将 ModelA
注册为 Base
.[=58 的“virtual subclass” =]
调用 ModelA.register(Base)
正在尝试将 Base
注册为 ModelA
的虚拟子 class,但 ModelA
已经是Base
的实际子 class,- 这就是您获得继承周期的原因。您不能让 classes X 和 Y 相互继承。
但是,由于 ModelA
明确是 Base
的子 class,您根本不需要调用 register
。你想要:
class ModelA(Base):
...
没有 register
调用(此处 ModelA
是 Base
的实际子 class),或者:
class ModelA:
...
Base.register(ModelA)
(这里ModelA
是一个独立的class,在Base
的继承层次之外,但它被注册为一个虚拟子class)。 Either/or - 两者都不是。
在任何一种情况下,issubclass(ModelA, Base)
都将是 True
。
__subclasses__()
不接收虚拟子 classes,只有实际的 - 所以如果你想使用它,你应该忘记 register()
并使 ModelA
成为 Base
的真正子 class(上面的第一个选项)。
(在我看来,这是整个 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
的 class 层次结构。
在最后一行,您没有实例化 class klass
指向的任何实例;该行应该是:
klass().run()
我的目录结构类似于以下内容:
.
├── main.py
├── model.py
└── models
├── __init__.py
├── model_a.py
└── model_b.py
model.py
包含一个抽象基础 Class:
from abc import ABCMeta, abstractmethod
class Base(metaclass=ABCMeta):
@abstractmethod
def run(self):
pass
在 models
文件夹中是此基础 class、model_a.py
和 model_b.py
的两个实现,它们将自己注册到主 Base
class。 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
的所有子 class 的字典,这样我就可以 select (通过我程序的 GUI)和 运行 它:
from model import Base
subclasses = Base.__subclasses__()
dct = {cls.__name__: cls for cls in subclasses}
klass = dct['ModelA']
klass.run()
但我无法让它工作。当我尝试执行派生的 classes 之一并且 main.py
中的字典为空时,我得到 RuntimeError: Refusing to create an inheritance cycle
。
我意识到这已经很晚了,但万一它对其他偶然发现这个的人有帮助...
你在这里遇到了一些问题:
你的 classes 在那个
register
调用中是错误的;只有在这种情况下调用Base.register(ModelA)
(而不是相反)才有意义,以便将ModelA
注册为Base
.[=58 的“virtual subclass” =]调用
ModelA.register(Base)
正在尝试将Base
注册为ModelA
的虚拟子 class,但ModelA
已经是Base
的实际子 class,- 这就是您获得继承周期的原因。您不能让 classes X 和 Y 相互继承。但是,由于
ModelA
明确是Base
的子 class,您根本不需要调用register
。你想要:class ModelA(Base): ...
没有
register
调用(此处ModelA
是Base
的实际子 class),或者:class ModelA: ... Base.register(ModelA)
(这里
ModelA
是一个独立的class,在Base
的继承层次之外,但它被注册为一个虚拟子class)。 Either/or - 两者都不是。在任何一种情况下,
issubclass(ModelA, Base)
都将是True
。__subclasses__()
不接收虚拟子 classes,只有实际的 - 所以如果你想使用它,你应该忘记register()
并使ModelA
成为Base
的真正子 class(上面的第一个选项)。(在我看来,这是整个 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
的 class 层次结构。在最后一行,您没有实例化 class
klass
指向的任何实例;该行应该是:klass().run()