我发现在Python中定义抽象类的方法有多种(略有不同)。我阅读了文档,也无法在stackoverflow上找到答案。
三个例子(见下面的代码)之间的主要区别是:
A
明确设置新的元类abc.ABCMeta
B
继承自abc.ABC
C
继承自objects
,但定义了@abc.abstractmethod
个类似乎A
和B
没有区别(即B
也有新的元类abc.ABCMeta
)。但是,类C
仍为type
类型。
没有为C
定义元类的影响是什么?什么时候需要定义元类,或者为不为抽象类定义abc.ABCMeta
元类是错误/错误的风格?尽管如此,班级C
似乎表达了我对ABC的期望。
import abc
class A(metaclass=abc.ABCMeta):
# Alternatively put __metaclass__ = abc.ABCMeta here
@abc.abstractmethod
def foo(self):
raise NotImplementedError
class B(abc.ABC):
@abc.abstractmethod
def foo(self):
raise NotImplementedError
class C(object):
@abc.abstractmethod
def foo(self):
raise NotImplementedError
class Aimpl(A):
def foo(self):
print("Aimpl")
class Bimpl(B):
def foo(self):
print("Bimpl")
class Cimpl(C):
#def foo(self):
# print("Cimpl")
pass
Aimpl().foo() # Aimpl
print(isinstance(Aimpl, A)) # False
print(issubclass(Aimpl, A)) # True
print(isinstance(Aimpl, abc.ABCMeta)) # True
print(type(A)) # <class 'abc.ABCMeta'>
print("---")
Bimpl().foo() # Bimpl
print(isinstance(Bimpl, B)) # False
print(issubclass(Bimpl, B)) # True
print(isinstance(Bimpl, abc.ABCMeta)) # True
print(type(B)) # <class 'abc.ABCMeta'>
print("---")
Cimpl().foo() # Cimpl
print(isinstance(Cimpl, C)) # False
print(issubclass(Cimpl, C)) # True
print(isinstance(Cimpl, abc.ABCMeta)) # False
print(type(C)) # <class 'type'>
print("---")
答案 0 :(得分:4)
abc.ABCMeta
类是实际执行abstractmethod
行为所必需的。它的目的是禁止实现任何不实现抽象方法的类。装饰器本身不能强制执行,元类在实例化时强制执行装饰器:
class Foo:
@abstractmethod
def bar(self):
pass
Foo() # works
但是:
class Foo(metaclass=ABCMeta):
@abstractmethod
def bar(self):
pass
Foo()
Traceback (most recent call last):
File "<input>", line 1, in <module>
TypeError: Can't instantiate abstract class Foo with abstract methods bar
因此,如果没有元类,abstractmethod
装饰器就不会做任何事情。
abc.ABC
只是一种简写,因此您可以Foo(ABC)
代替Foo(metaclass=ABCMeta)
,这就是全部:
具有
ABCMeta
作为其元类的辅助类。有了这堂课, 只需从ABC
派生即可创建抽象基类 避免有时混淆元类使用[..]