定义抽象类的三种方式的差异

时间:2018-05-29 07:48:04

标签: python python-3.x abstract-class

我发现在Python中定义抽象类的方法有多种(略有不同)。我阅读了文档,也无法在stackoverflow上找到答案。

三个例子(见下面的代码)之间的主要区别是:

  • A明确设置新的元类abc.ABCMeta
  • B继承自abc.ABC
  • C继承自objects,但定义了@abc.abstractmethod个类

似乎AB没有区别(即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("---")

1 个答案:

答案 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派生即可创建抽象基类   避免有时混淆元类使用[..]

     

https://docs.python.org/3/library/abc.html#abc.ABC