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

Xia*_*nni 3 python abstract-class python-3.x

我在网上看代码的时候,遇到过以下使用抽象类的情况:

from abc import abstractmethod,ABCMeta
class Generator(object,metaclass=ABCMeta):
    @abstractmethod
    def generate(self):
        raise NotImplementedError("method not implemented")
generator=Generator()
generator.generate()
Run Code Online (Sandbox Code Playgroud)

正如预期的那样,返回以下错误:

TypeError: Can't instantiate abstract class Generator with abstract methods generate

但如果我这样写(唯一的区别在第二行

from abc import abstractmethod,ABCMeta
class Generator(object):
    @abstractmethod
    def generate(self):
        raise NotImplementedError("method not implemented")
generator=Generator()
generator.generate()
Run Code Online (Sandbox Code Playgroud)

虽然错误信息有变化,

NotImplementedError: method not implemented

当我实现该generate方法时,上述两种方式都Generator正确执行,

class GeneticAlgorithm(Generator):
    def generate(self):
        print("ABC")
ga=GeneticAlgorithm()
ga.generate()
Run Code Online (Sandbox Code Playgroud)
>>> ABC
Run Code Online (Sandbox Code Playgroud)

那么为什么我们需要声明呢metaclass=ABCMeta

我从GeeksforGeeks了解到一些事情

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

但这还是没有让我明白声明的必要性metaclass=ABCMeta,感觉@abstractmethod修改一下方法就够了。

Sha*_*ger 5

您“需要”在实例化时metaclass=ABCMeta强制执行规则。

generator=Generator()  # Errors immediately when using ABCMeta
generator.generate()   # Only errors if and when you call generate otherwise
Run Code Online (Sandbox Code Playgroud)

想象一下,如果该类有多个抽象方法,但只有其中一些在子类中实现。它可能会工作很长一段时间,并且只有当您调用未实现的方法时才会出错。在依赖 ABC 之前急切地失败通常是一件好事,同样,函数引发异常通常比仅仅返回None来指示失败更好;您希望在出现问题时立即知道,而不是在不知道错误的最终原因的情况下出现奇怪的错误。

旁注:有一种比明确使用metaclass=ABCMeta语法更简洁的方法来成为 ABC:

from abc import abstractmethod, ABC

class Generator(ABC):
Run Code Online (Sandbox Code Playgroud)

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