Python: 抽象层级 类 没有抽象方法

Python: hierarchy of abstract classes without abstract methods

那么,问题来了:

  1. 我想定义一个抽象class,比方说AbstractA,它不需要子classes来实现它的任何方法,而是以扩展其功能。根据 Java 接口 class.

  2. 此外,我希望能够创建具有相同属性的 AbstractA 的抽象子 class,比方说 AbstractB,但有些方法重新定义或扩展基础 class 方法。

我不想将 class (AbstractA) 抽象化,例如through the check of class name in __init__ or __new__,因为这需要抽象子class (AbstractB) 来重新定义该方法及其主要功能,即新实例的构造或初始化。或者调用 super().__init__(...) ,我也希望避免这种情况(也许我在这里错了)。

所以,我想要这样的东西:

class AbstractA:
    def __init__(self):
        # do initialization stuff

    def very_common_method(self, ...):
        # do very common stuff

class AbstractB(AbstractA):
    # do not duplicate initialization stuff here, inherit instead

    def less_common_method(self, ...):
        # do less common stuff

class AX(AbstractA):
    def specific_method_1(self, ...):

class BX(AbstractB):
    def specific_method_2(self, ...):

# Instantiating AbstractA or AbstractB should result in error.
# Instantiating AX or BX should not.

下面我有一个可能的解决方案。 有什么我忽略的缺点吗?更好的解决方案?

谢谢!

可能的解决方案如下:

class AbstractA:
    _is_abstract = True

    def __init__(self):
        if self._is_abstract:
            raise RuntimeError("Abstract class instantiation.")
        # do initialization stuff

    def __init_subclass__(self):   # is called every time class is subclassed
        self._is_abstract = False  # thus makes sure abstract check fails on a subclass

class AbstractMixin:
    def __init_subclass__(self):
        self._is_abstract = True

class AbstractB(AbstractMixin, AbstractA):  # AbstractMixin takes precendence on MRO,
    # inherit __init__                      # so the class abstract check returns True.

    def __init_subclass__(self):
        self._is_abstract = False

class A(AbstractA):
    pass

class B(AbstractB):
    pass

AbstractA()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 5, in __init__
RuntimeError: Abstract class instantiation.

AbstractB()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 5, in __init__
RuntimeError: Abstract class instantiation.

A()
<__main__.A object at 0x7f0bba5112e8>

B()
<__main__.B object at 0x7f0bba511438>
class A(object):

    def __init__(self):
        if self.__class__ == A:
            raise RuntimeError("Abstract class instantiation.")
        print(self.__class__.__name__)


class B(A):
    pass


>>> A()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 5, in __init__
RuntimeError: Abstract class instantiation.
>>> B()
B
<__main__.B object at 0x7f8c816a58d0>
>>> 

在 Python 中,您可能会将 "abstract" 基础 class 实现为混入。您不需要做任何特别的事情;按照惯例,您会在名称中添加 Mixin 以表明它不打算直接实例化,而只是用作其他 class 的基础 class。

class AMixin:
    def __init__(self):
        # do initialization stuff

    def very_common_method(self, ...):
        # do very common stuff

class BMixin(AMixin):
    # do not duplicate initialization stuff here, inherit instead

    def less_common_method(self, ...):
        # do less common stuff

class AX(AMixin):
    def specific_method_1(self, ...):

class BX(BMixin):
    def specific_method_2(self, ...):

class Foo:
    ...

class Bar(Foo, BMixin):
    ...