python - 如果子类重写了Python中父类的方法,如何引发错误?

标签 python inheritance overriding subclass

我正在做一个类,它将成为另一个类的基础,我想禁止某些方法在某些情况下被覆盖,但我只是不知道该怎么做。

最佳答案

我将向您展示三种从“不太糟糕”到最干净的方法(在我看来)。

1。类装饰器

实现此目的的一种方法是使用“类装饰器”来比较类本身及其父类的方法:

from inspect import isfunction


def should_not_override_parents_method(cls):
    parents_methods = set(k for k, v in cls.__base__.__dict__.items() if isfunction(v))
    class_methods = set(k for k, v in cls.__dict__.items() if isfunction(v))
    intersection = parents_methods & class_methods

    if intersection:
        raise Exception(
            f"class {cls.__name__} should not implement parents method: "
            f"'{', '.join(intersection)}'"
        )
    return cls


class A:
    def fn_1(self):
        print("A : inside fn_1")


@should_not_override_parents_method
class B(A):
    def fn_1(self):
        print("B : inside fn_1")

    def fn_2(self):
        print("B : inside fn_2")

2。 __init_subclass__

from inspect import isfunction


class A:
    def __init_subclass__(cls, **kwargs):
        parents_methods = set(
            k for k, v in cls.__base__.__dict__.items() if isfunction(v)
        )
        class_methods = set(k for k, v in cls.__dict__.items() if isfunction(v))
        intersection = parents_methods & class_methods

        if intersection:
            raise Exception(
                f"class {cls.__name__} should not implement parents method: "
                f"'{', '.join(intersection)}'"
            )

    def fn_1(self):
        print("A : inside fn_1")


class B(A):
    def fn_1(self):
        print("B : inside fn_1")

    def fn_2(self):
        print("B : inside fn_2")

注意:这些只会阻止子类在创建阶段覆盖父类的方法。这意味着创建类后,您可以动态地将这些方法添加到其中。为了防止这种情况,您可以创建自定义元类并覆盖 __setattr__方法也是:

3。元类

from inspect import isfunction


class Prevent(type):
    @staticmethod
    def _check_methods(parent_dict, child_dict, child_name):
        parents_methods = set(k for k, v in parent_dict.items() if isfunction(v))
        class_methods = set(k for k, v in child_dict.items() if isfunction(v))
        intersection = parents_methods & class_methods
        if intersection:
            raise Exception(
                f"class {child_name} should not implement parents method: "
                f"'{', '.join(intersection)}'"
            )

    def __new__(cls, name, bases, mapping, **kwargs):
        if bases:
            parent = bases[0]
            Prevent._check_methods(parent.__dict__, mapping, name)
        class_object = super().__new__(cls, name, bases, mapping)
        return class_object

    def __setattr__(cls, name, value) -> None:
        if name in cls.__base__.__dict__:
            raise Exception(
                f"class {cls.__name__} should not have parents method: {name}"
            )
        super().__setattr__(name, value)


class A(metaclass=Prevent):
    def fn_1(self):
        print("A : inside fn_1")


class B(A):
    def fn_1(self):
        print("B : inside fn_1")

    def fn_2(self):
        print("B : inside fn_2")

输出:

Traceback (most recent call last):
  File "<>", line 36, in <module>
    class B(A):
  File "<>", line 19, in __new__
    Prevent._check_methods(parent.__dict__, mapping, name)
  File "<>", line 11, in _check_methods
    raise Exception(
Exception: class B should not implement parents method: 'fn_1'

现在值得一提的是,从 Python 3.8 开始,有一个名为 @typing.final 的装饰器。这提示您不应在子类中重写此方法。当然,在运行时这样做没有任何限制。

from typing import final


class A:
    @final
    def fn_1(self):
        print("A : inside fn_1")


class B(A):
    def fn_1(self):
        print("B : inside fn_1")

    def fn_2(self):
        print("B : inside fn_2")

关于python - 如果子类重写了Python中父类的方法,如何引发错误?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69766572/

相关文章:

c++ - 从基类静态转换为派生类后找不到成员函数

reactjs - 在非弹出的 create-react-app 中覆盖 eslint 设置?

python - 计算字典列表的最小值和最大值以规范化字典值

python - 将 DataFrames 与 Pks 的所有组合合并

java - 使用 Jackson 组合而不是继承

c++ - 虚拟继承 : Why does it work when only one base class has "virtual" keyword? 有没有更好的办法?

c# - 使用不同名称重写最终 (IL)/密封 (C#) 方法是否合法?

inheritance - Golang 继承和方法覆盖

python - 使用自定义身份验证修改请求参数

python - Blender 2.7 MacOS 控制台错误