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)
一种选择是使用元类:
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。