为什么子类的实例化在__init_subclass__中起作用,尽管它是缺少方法的抽象基类?

时间:2019-05-29 10:22:43

标签: python python-3.7

我正在尝试编写一个简单的插件系统。

a)为此,我使用了3.6魔术函数__init_subclass__ https://stackoverflow.com/a/41924331/1506569找到了以下代码,该函数改编自PEP 487,该函数将定义中的每个类都注册在{{1}中的父类中}列表。

b)现在,我想“强制”插件的编写者实现一种特定的方法,该方法将由我的程序调用。理想情况下,这将在导入时警告用户,他的插件将不起作用,但不会阻止程序运行。为此,我尝试将ABC作为父类添加到插件,并添加plugins

我最初尝试使用ABC和@abstractmethod

__init_subclass__

这里的问题是,实例化from abc import ABC, abstractmethod class Plugin(ABC): plugins = [] @classmethod def __init_subclass__(cls, **kwargs): super().__init_subclass__(**kwargs) try: __class__.plugins.append(cls()) # Does not raise exception except Exception as e: print("Warning: Your plugin might not work, missing abstract method") @abstractmethod def do_something(self): ... class Render(Plugin): def __init__(self): print("Render init") # does not implement 'do_something' for plugin in Plugin.plugins: plugin.do_something() # Calls 'do_something' on Render, without raising an exception 不会引发异常,而是将实例化的__class__.plugins.append(cls())对象添加到Render列表中。 调用函数plugins(底部的循环)也不会引发异常。它什么都不做。

我在这里找到了一个解决方案:https://stackoverflow.com/a/54545842/1506569,它只是比较基类和子类上的函数对象是否不同(通过使用 class 和cls)。但这使得从ABC继承成为不必要,并且看起来比需要的更为复杂。

没有ABC的第二次尝试:

Render.do_something

此版本有效,但对我来说却令人困惑,看起来它可能会进一步中断?

我错过了一种方法吗?为什么实例化起作用? 抱歉,如果我错过了类似的问题,我尝试搜索了很长时间。

1 个答案:

答案 0 :(得分:0)

如果只想强制子类实现方法,那么@abstractmethod就足够了。您不需要init_subclass。您的代码是正确的,但是您尚未实例化 Render。当创建 objects 而不是类时,抽象方法将给您一个错误。如果您写Render(),实际上会得到一个错误

  

无法使用抽象方法do_something实例化抽象类Render