我正在做一个类,它将成为另一个类的基础,我想禁止某些方法在某些情况下被覆盖,但我只是不知道该怎么做。
最佳答案
我将向您展示三种从“不太糟糕”到最干净的方法(在我看来)。
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/