Python: hierarchy of abstract classes without abstract methods

半腔热情 提交于 2019-12-25 01:37:52

问题


So, here is a problem:

  1. I want to define an abstract class, let's say AbstractA, which does not require subclasses to implement any of its methods, but rather to extend its functionality. In terms of Java that would be interface class.

  2. Moreover, I want to be able to create an abstract subclass, let's say AbstractB, of the AbstractA with the same properties, but some methods redefining or extending base class methods.

I don't want though to make class (AbstractA) abstract e.g. through the check of class name in __init__ or __new__, because that would require abstract subclass (AbstractB) to redefine that method along with it's main functionality, i.e. construction or initialization of a new instance. Or to call super().__init__(...) which I'd prefer to avoid as well (maybe I'm wrong here).

So, I want something like that:

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.

Below I have a possible solution. Is there any disadvantages I overlook? Better solution?

Thanks!


回答1:


Here's possible solution:

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>



回答2:


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>
>>> 




回答3:


In Python, you would probably implement the "abstract" base classes as mix-ins. There's nothing special you need to do; by convention, you would add Mixin to the name to indicate that it isn't meant to be instantiated directly, but simply used as a base class for other classes.

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):
    ...


来源:https://stackoverflow.com/questions/59316282/python-hierarchy-of-abstract-classes-without-abstract-methods

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!