首页 > 解决方案 > Python ABC classes: One of multiple methods has to be overridden

问题描述

In Python, I have an abstract base class which has four methods, of which at least one has to be overwritten. Is it possible to somehow implement this with the @abstractmethod decorator or something similar?

Here is a stripped down version of the base class:

from abc import ABCMeta

class Base(metaclass=ABCMeta):
    def __init__(self, var):
        self.var = var

    def a(self, r):
        return self.var - self.b(r)

    def b(self, r):
        return self.var * self.c(r)

    def c(self, r):
        return 1. - self.d(r)

    def d(self, r):
        return self.a(r) / self.var

The four methods have some kind of cyclic dependency and a subclass has to override at least one of these methods. The rest of the methods then work from the base class.

It might seem a bit strange, but it makes perfectly sense in the application I'm working on.

标签: pythonabstract-classabc

解决方案


感谢@NChauhan 的提示,我想出了以下解决方案,并且感谢@NChauhan 和@greeeeeeen 的第二个提示,该解决方案变得更短且更具可读性:

from abc import ABCMeta


class Base(metaclass=ABCMeta):
    def __init__(self, var):
        self.var = var

    def __init_subclass__(cls):
        super().__init_subclass__()

        def a(self, r):
            return self.var - self.b(r)

        def b(self, r):
            return self.var * self.c(r)

        def c(self, r):
            return 1. - self.d(r)

        def d(self, r):
            return self.a(r) / self.var

        if not hasattr(cls, 'a'):
            cls.a = a
        if not hasattr(cls, 'b'):
            cls.b = b
        if not hasattr(cls, 'c'):
            cls.c = c
        if not hasattr(cls, 'd'):
            cls.d = d

        if not any(hasattr(cls, method) for method in ('a', 'b', 'c', 'd')):
            raise TypeError(f"Can't instantiate class '{cls.__name__}', " +
                            "without overriding at least on of the methods " +
                            "'a', 'b', 'c', or 'd'.")

如果我不分配方法中的四个方法__init_subclass__hasattr就会返回True,因为这些方法会被继承。


推荐阅读