包装Python超类的所有方法

ElR*_*udi 3 python inheritance class

如果我无法更改超类的代码,有没有办法包装超类的所有方法?

作为一个最小的工作示例,考虑这个基类Base,它有许多返回自身新实例的方法,以及派生类Child

class Base:
    
    def __init__(self, val):
        self.val = val
        
    def newinst_addseven(self):
        return Base(self.val + 7)
    
    def newinst_timestwo(self):
        return Base(self.val * 2)
    
    # ...

class Child(Base):
    
    @property
    def sqrt(self):
        return math.sqrt(self.val)
Run Code Online (Sandbox Code Playgroud)

这里的问题是调用返回, 而不是 的childinstance.newinst_addseven()实例。BaseChild

有没有办法包装Base类的方法以强制返回该类型的值Child

有了这样的包装:

def force_child_i(result):
    """Turn Base instance into Child instance."""
    if type(result) is Base:
        return Child(result.val)
    return result

def force_child_f(fun):
    """Turn from Base- to Child-instance-returning function."""
    def wrapper(*args, **kwargs):
        result = fun(*args, **kwargs)
        return force_child_i(result)
    return wrapper
Run Code Online (Sandbox Code Playgroud)

非常感谢!


PS:我目前所做的是查看Base源代码并Child直接添加方法,这不太可维护:

Child.newinst_addseven = force_child_f(Base.newinst_addseven)
Child.newinst_timestwo = force_child_f(Base.newinst_timestwo)
Run Code Online (Sandbox Code Playgroud)

Yev*_*ych 6

一种选择是使用元类:

class ChildMeta(type):
    def __new__(cls, name, bases, dct):
        child = super().__new__(cls, name, bases, dct)
        for base in bases:
            for field_name, field in base.__dict__.items():
                if callable(field):
                    setattr(child, field_name, force_child(field))
        return child


class Child(Base, metaclass=ChildMeta):
    pass
Run Code Online (Sandbox Code Playgroud)

Base它会自动用你的装饰器包装所有s 方法force_child