当在Python中使用抽象类时,为什么要声明metaclass = abc.ABCMeta?

3
当我在线阅读代码时,我遇到了以下使用抽象类的情况:
from abc import abstractmethod,ABCMeta
class Generator(object,metaclass=ABCMeta):
    @abstractmethod
    def generate(self):
        raise NotImplementedError("method not implemented")
generator=Generator()
generator.generate()

以下错误信息是预期的:
TypeError: 无法实例化带有抽象方法 generate 的抽象类 Generator 但如果我这样写(唯一不同的是第二行):
from abc import abstractmethod,ABCMeta
class Generator(object):
    @abstractmethod
    def generate(self):
        raise NotImplementedError("method not implemented")
generator=Generator()
generator.generate()

虽然错误信息发生了变化, NotImplementedError: 方法未实现 但当我实现了generate方法时,上述两种Generator的方式都能正常执行。
class GeneticAlgorithm(Generator):
    def generate(self):
        print("ABC")
ga=GeneticAlgorithm()
ga.generate()

>>> ABC

那么为什么我们需要声明metaclass=ABCMeta
我从GeeksforGeeks了解到一些东西。

ABCMeta元类提供了一个名为register的方法,可以由其实例调用。 通过使用此register方法,任何抽象基类都可以成为任意具体类的祖先。

但这仍然不能让我理解声明metaclass=ABCMeta的必要性,感觉@abstractmethod 修改该方法就足够了。
2个回答

5
你需要使用metaclass=ABCMeta在实例化时执行规则。
generator=Generator()  # Errors immediately when using ABCMeta
generator.generate()   # Only errors if and when you call generate otherwise

假设某个类有多个抽象方法,而其中只有一些在子类中被实现。它可能会运行一段时间,直到你调用一个未实现的方法才出错。在依赖于 ABC 前先进行严格的失败处理通常是很好的做法,就像函数抛出异常而不仅是返回 None 来表示失败一样;你希望尽早知道出了问题,而不是在以后遇到一个奇怪的错误时却不知道其根本原因。
附带说明:有一种更为简洁的方式可以成为 ABC,而不必显式使用 metaclass=ABCMeta 语法:
from abc import abstractmethod, ABC

class Generator(ABC):

Python几乎总是会创建空的基类,使用元类来简化使用(特别是在从2到3的过渡期间,在那里没有兼容两者都工作的元类语法,直接继承是唯一可行的方法)。


1
第二个例子,
from abc import abstractmethod,ABCMeta
class Generator(object):
    @abstractmethod
    def generate(self):
        raise NotImplementedError("method not implemented")
generator=Generator()
generator.generate()  # HERE it raises

第一个示例中没有以任何方式使用@abstractclass修饰符。只有在调用generate()函数时才会引发NotImplemetedError异常,而在第一个示例中在实例化(generator=Generator())时就会引发错误。

要使用@abstractmethod,类必须具有元类ABCMeta(或从此类继承,例如ABC)。

顺便说一句,还有一些方法可以更早地检查方法是否已实现(在类定义时) ,例如使用__init_subclass__或通过定义自定义元类并修改其__new__方法。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接