python - 使具体类抽象,保留构造函数

标签 python oop inheritance abstract-class

假设你有一个具体类

class Knight(object):
    def __init__(self, name):
        self._name = name
    def __str__(self):
        return "Sir {} of Camelot".format(self.name)

现在碰巧类层次结构必须改变。 Knight 应该成为一个抽象基类,为各种城堡的骑士提供一堆具体的子类。很简单:

class Knight(metaclass=ABCMeta):  # Python 3 syntax
    def __str__(self):
        return "Sir {} of {}".format(self.name, self.castle)
    @abstractmethod
    def sing():
        pass

class KnightOfTheRoundTable(Knight):
    def __init__(self, name):
        self.name = name
    @property
    def castle(self):
        return "Camelot"
    @staticmethod
    def sing():
        return ["We're knights of the round table",
                "We dance whenever we're able"]

但现在所有使用Knight("Galahad") 构造Knight 的代码都被破坏了。相反,我们可以保持 Knight 不变,并引入一个 BaseKnight,但是随后检查 isinstance(x, Knight) 的代码应该继续工作任何骑士都可能需要改为检查 BaseKnight

如何将一个具体类变成一个抽象类,同时避免构造函数和 isinstance 检查?

最佳答案

使现有类成为基类,但是overload __new__在尝试实例化基类时返回子类:

class Knight(metaclass=ABCMeta):
    def __new__(cls, *args, **kwargs):
        if cls is Knight:
            # attempt to construct base class, defer to default subclass
            return KnightOfTheRoundTable(*args, **kwargs)
        else:
            obj = super(Knight, cls).__new__(cls)
            obj.__init__(*args, **kwargs)
            return obj
    def __str__(self):
        return "Sir {} of {}".format(self.name, self.castle)
    @abstractmethod
    def sing():
        pass

现在 Knight("Galahad") 继续工作但返回一个 KnightOfTheRoundTableisinstance(Knight("Robin"), Knight) 返回 True,与 isinstance(x, Knight) 检查任何其他子类实例一样.

关于python - 使具体类抽象,保留构造函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26462167/

相关文章:

java - 如何重用 Spring Data JpaRepository 接口(interface)

ios - 类不符合协议(protocol)

java - 从基类构造函数创建子类实例

python - Numpy/Scipy 中大气数据的快速 3D 插值

python - 在 Fastapi 中,在哪里放置用于身份验证的依赖项/依赖项?

javascript - $$ 和 $ 之间的区别

postgresql - SQLAlchemy 无法找到与非特权用户的外键关系

objective-c - 对象(持有 NSMutableArray)在父/子类中具有不同的内容

python - xpath 有一个空值,这会弄乱列表

python - Landsat-8 图像的 RGB 合成