调用子方法时如何强制调用父方法?

How to enforce mandatory parent method call when calling child method?

我想要的是强制当子 class 从父继承并且它覆盖父方法而不显式调用它时,会引发错误。 错误 class 初始化或调用方法时可能会引发错误。

目标是确保 Mother class 的用户执行了 mother 方法中存在的一些操作。

示例

class Mother():
    def necessary_method(self):
         # do some necessary stuff

class GoodChild(Mother):
    def necessary_method(self):
        # necessary parent call
        super().necessary_method()

class BadChild(Mother):
    def necessary_method(self):
         # no parent call
         return

调用时:

good = GoodChild()
# works fine
bad = BadChild()
# exception could be raised here

good.necessary_method()
# works fine
bad.necessary_method()
# exception could be raised here

这真的可能吗? 欢迎任何答案或解决方法。

是的,这绝对是可能的,至少在运行时是这样。你可以创建一个 Metaclass 来修改 类 的创建方式,这个想法是通过添加一个 mother_method_called 标志来更改 necessary_method 签名,该标志只有在Mother 版本被调用,否则它会引发一个 Value Error。例如 python3:

class MotherMetaClass(type):
    def __new__(cls, name, bases, attrs):
        method_name = 'necessary_method'
        mother_class_name = 'Mother'
        original_necessary_method = attrs.get(method_name)

        def necessary_method_validated(*args, **kwargs):
            original_necessary_method(*args, **kwargs)

            if name == mother_class_name:
                cls.mother_method_called = True
            else:
                if not cls.mother_method_called:
                    raise ValueError(f'Must call "super()" when overriding "{method_name}".')
                cls.mother_method_called = False

        attrs[method_name] = necessary_method_validated

        return super().__new__(cls, name, bases, attrs)


class Mother(metaclass=MotherMetaClass):
    def necessary_method(self):
        print('Parent method called.')


class GoodChild(Mother):
    def necessary_method(self):
        super().necessary_method()
        print('Good child method called.')


class BadChild(Mother):
    def necessary_method(self):
        print("Bad child method called.")


a = GoodChild()
a.necessary_method()  # it's going to work properly


b = BadChild()
b.necessary_method()  # it's going to raise Value Error