为什么我们在python中使用抽象class时声明metaclass=abc.ABCMeta?
Why we declare metaclass=abc.ABCMeta when use abstract class in python?
我在网上看代码的时候遇到过以下使用abstract的情况类:
from abc import abstractmethod,ABCMeta
class Generator(object,metaclass=ABCMeta):
@abstractmethod
def generate(self):
raise NotImplementedError("method not implemented")
generator=Generator()
generator.generate()
如预期的那样返回以下错误:
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()
虽然报错信息有变化,
NotImplementedError: method not implemented
我在实现generate
方法时,Generator
上面两种方式都正确执行了,
class GeneticAlgorithm(Generator):
def generate(self):
print("ABC")
ga=GeneticAlgorithm()
ga.generate()
>>> ABC
那么为什么我们需要语句 metaclass=ABCMeta
?
我从 GeeksforGeeks 那里了解到一些事情
ABCMeta metaclass provides a method called register method that can be invoked by its instance. By using this register method, any abstract base class can become an ancestor of any arbitrary concrete class.
但这还是没有让我理解声明metaclass=ABCMeta
的必要性,感觉@abstractmethod
修改方法就够了
第二个例子,
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
,class 必须有元 class ABCMeta
(或者它必须继承自 class,例如ABC
).
顺便说一句,有一些方法可以检查方法是否更快地实现(在 class 定义上),例如使用 __init_subclass__
或通过定义自定义元 class并修改其 __new__
方法。
您“需要”metaclass=ABCMeta
在实例化时执行规则。
generator=Generator() # Errors immediately when using ABCMeta
generator.generate() # Only errors if and when you call generate otherwise
想象一下,如果 class 有几个抽象方法,只有其中一些在子对象中实现。它可能会工作很长一段时间,只有当你开始调用一个未实现的方法时才会出错。在依赖 ABC 之前急于失败通常是一件好事,同样的,函数引发异常通常比返回 None
来指示失败更好;您想在出现问题时立即知道,而不是在不知道错误的最终原因的情况下得到奇怪的错误。
Side-note:有一种比显式使用 metaclass=ABCMeta
语法更简洁的 ABC 方法:
from abc import abstractmethod, ABC
class Generator(ABC):
Python 几乎总是使用 metaclass 的空基 classes 来简化使用(特别是在 2 到 3 过渡时期,那里没有兼容的 metaclass 语法在两者中都有效,而直接继承是唯一有效的方法)。
我在网上看代码的时候遇到过以下使用abstract的情况类:
from abc import abstractmethod,ABCMeta
class Generator(object,metaclass=ABCMeta):
@abstractmethod
def generate(self):
raise NotImplementedError("method not implemented")
generator=Generator()
generator.generate()
如预期的那样返回以下错误:
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()
虽然报错信息有变化,
NotImplementedError: method not implemented
我在实现generate
方法时,Generator
上面两种方式都正确执行了,
class GeneticAlgorithm(Generator):
def generate(self):
print("ABC")
ga=GeneticAlgorithm()
ga.generate()
>>> ABC
那么为什么我们需要语句 metaclass=ABCMeta
?
我从 GeeksforGeeks 那里了解到一些事情
ABCMeta metaclass provides a method called register method that can be invoked by its instance. By using this register method, any abstract base class can become an ancestor of any arbitrary concrete class.
但这还是没有让我理解声明metaclass=ABCMeta
的必要性,感觉@abstractmethod
修改方法就够了
第二个例子,
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
,class 必须有元 class ABCMeta
(或者它必须继承自 class,例如ABC
).
顺便说一句,有一些方法可以检查方法是否更快地实现(在 class 定义上),例如使用 __init_subclass__
或通过定义自定义元 class并修改其 __new__
方法。
您“需要”metaclass=ABCMeta
在实例化时执行规则。
generator=Generator() # Errors immediately when using ABCMeta
generator.generate() # Only errors if and when you call generate otherwise
想象一下,如果 class 有几个抽象方法,只有其中一些在子对象中实现。它可能会工作很长一段时间,只有当你开始调用一个未实现的方法时才会出错。在依赖 ABC 之前急于失败通常是一件好事,同样的,函数引发异常通常比返回 None
来指示失败更好;您想在出现问题时立即知道,而不是在不知道错误的最终原因的情况下得到奇怪的错误。
Side-note:有一种比显式使用 metaclass=ABCMeta
语法更简洁的 ABC 方法:
from abc import abstractmethod, ABC
class Generator(ABC):
Python 几乎总是使用 metaclass 的空基 classes 来简化使用(特别是在 2 到 3 过渡时期,那里没有兼容的 metaclass 语法在两者中都有效,而直接继承是唯一有效的方法)。