我想在python中自动将函数调用转发给子类,以便父类具有所述函数,然后将调用转发给子类并将结果返回给调用者。像这样的东西:
class child:
def __init__(self):
self.b = 1
def dosomething(self, a=1):
print("child dosomething", a, self.b)
return 'returning stuff'
class parent:
def __init__(self):
self.child = child()
# I could do this for every func in child:
def dosomething(self, *args, **kwargs):
return self.child.dosomething()
p = parent()
p.dosomething()
因为我不想冒打字错误或忘记更新父级的风险,所以这应该自动完成,而不是像上面所示的那样,特别是如果子级有很多功能的话。
我可以通过为父类实现 getattr 来完成类似的事情,但是这样我的 IDE 和解释器都不知道父类/子类中的方法,这不是我想要的。
我探索的另一种方法是让孩子使用所有方法
def get_methods(x):
return [
[method, getattr(x, method)]
for method in dir(x)
if callable(getattr(x, method))
if not method.startswith("_")
]
然后以某种方式将它们附加到我的父类中。 我可以使用
setattr(parent,'dosomething',func_from_get_methods(child))
来做到这一点
然后像以前一样调用它,但这行不通,因为父级没有 self.b.
那么,有没有Pythonic的方法可以做到这一点?
附注我不是在谈论子类化。
如果有人遇到这个“问题”...... 经过一些睡眠和一些修补后,我想出了一个解决方案。
原则上,这个想法是双重的:
我的代码:
def get_methods(x):
# returns all methods of class x (or multiple classes)
res = {}
xs = x if isinstance(x, list) else [x]
for x in xs:
for method in dir(x):
try:
if callable(getattr(x, method)) and not method.startswith("_"):
res[method] = getattr(x, method)
except:
print(f'Skipping {method} due to error')
return res
def add_pass_through_functions(parent_class, child_classes: list, child_variable_name: str):
# adds all methods of the child_class(es) to the variable child_variable_name which belongs to parent_class
methods = get_methods(child_classes)
for name, method in methods.items():
def wrap(func, doc):
def f(self, *args, **kwargs):
return getattr(getattr(self, child_variable_name), func)(*args, **kwargs)
f.__doc__ = doc
return f
func = wrap(name, method.__doc__)
setattr(parent_class, name, func)
class Child:
def __init__(self):
self.a = 1
def dosomething(self, a=1):
print("child dosomething", a)
return 'returning stuff'
class Parent(Child): # by subclassing Child I get all methods in the autocomplete
def __init__(self):
self.child = Child()
add_pass_through_functions(parent_class=Parent, child_classes=Child, child_variable_name='child')
parent = Parent()
parent.dosomething()