簡體   English   中英

如何確保在 Python 的子類方法上調用超級方法?

[英]How do I make sure a super method is called on child classes method on Python?

如何確保在父 class 方法中調用super覆蓋父方法的子方法? 我在除 Python 以外的其他語言中發現了這個問題。

據我所知,沒有辦法強制子 class 方法在覆蓋它時必須調用父 class 方法。

盡管如此,解決方法可能是使用調用重寫方法的裝飾器。

基於這個答案

import inspect 


def get_class_that_defined_method(meth):
    if inspect.ismethod(meth):
        for cls in inspect.getmro(meth.__self__.__class__):
            if meth.__name__ in cls.__dict__:
                return cls
    if inspect.isfunction(meth):
        return getattr(inspect.getmodule(meth),
                       meth.__qualname__.split('.<locals>', 1)[0].rsplit('.', 1)[0],
                       None)
    return None  


def override(func):
    def wrapper(*args, **kwargs):
        cls = get_class_that_defined_method(func)
        if hasattr(cls.__base__, func.__name__):
            getattr(cls.__base__, func.__name__)(*args, **kwargs)
        return func(*args, **kwargs)

    return wrapper

這可以按如下方式使用。

class A:
    def method(self):
        print("call A.method")


class B(A):
    @override
    def method(self):
        print("call B.method")


B().method()
# call A.method
# call B.method

這可以通過使用decoratormetaclass來實現

import inspect


def my_decorator(func):
    def wrapper(self, *args, **kwargs):
        has_super = False
        for line in inspect.getsource(func).split('\n'):
            if line.strip().startswith("super"):
                has_super = True
                break
        if not has_super:
            super_method = getattr(super(self.__class__, self), func.__name__, None)
            if super_method:  
                super_method(*args, **kwargs)
        func(self, *args, **kwargs)
    return wrapper


class MyMeta(type):

    def __new__(cls, name, bases, local):
        for attr in local:
            if callable(local[attr]):
                local[attr] = my_decorator(local[attr])
        return super().__new__(cls, name, bases, local)


class BaseClass:
    
    def __init__(self):
        print("BaseClass __init__")

    def method1(self):
        print("BaseClass method1")

    def method2(self):
        print("BaseClass method2")


class Child(BaseClass, metaclass=MyMeta):

    def __init__(self):
        print("Child __init___")

    def method1(self):
        print("Child method1")

    def method2(self):
        print("Child method2")
        super().method2()


if __name__=="__main__":
    a = Child()
    a.method1()
    a.method2()

Output

BaseClass __init__
Child __init___
BaseClass method1
Child method1
Child method2
BaseClass method2

雖然您不能強制調用超類,但您可以做的是在覆蓋另一個 function 時強制調用一個:

class Parent:
    def other_method(self):
        # code that would be in overridden function should be placed here
        print("Hello from parent!")

    def method(self):
        pass

    def run_method(self):
        self.other_method()
        self.method()


class Child(Parent):
    def method(self):
        print("Hello from child!")


myChild= Child()
# calling method() here will not have the desired effect, one needs to call run_method()
myChild.run_method()

這將產生以下 output:

Hello from parent!
Hello from child!

子方法在不調用super() ) 的情況下覆蓋method() ) 。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM