我希望创建一个动态包装类,该类使用对象中的数据公开来自提供对象的 API 调用。
静态地看起来像这样:
class Concrete:
def __init__(self, data):
self.data = data
def print_data(self):
print(self.data)
class Wrapper:
'''
One day this will wrap a variety of objects. But today
it can only handle Concrete objects.
'''
def wrap_it(self, concrete):
self.cco = concrete # concreteobject=cco
def print_data(self):
self.cco.print_data()
cco = Concrete(5)
wcco = Wrapper()
wcco.wrap_it(cco)
wcco.print_data()
生产
5
我想弄清楚如何做同样的事情,但让 wrap_it
动态的。它应该搜索具体对象查找函数,并创建同名函数在具体对象中调用相同的函数。
我想解决方案涉及inspect.signature
或至少使用*args
和**kwargs
,但我还没有看到一个关于如何将所有这些放在一起的示例。
您可以使用 __getattr__
magic 方法来挂钩获取未定义的属性,并将它们转发到具体对象:
class DynamicWrapper():
def wrap_it(self, concrete):
self.cco = concrete
def __getattr__(self, k):
def wrapper(*args, **kwargs):
print(f'DynamicWrapper calling {k} with args {args} {kwargs}')
return getattr(self.cco, k)(*args, **kwargs)
if hasattr(self.cco, k):
return wrapper
else:
raise AttributeError(f'No such field/method: {k}')
cco = Concrete(5)
dwcco = DynamicWrapper()
dwcco.wrap_it(cco)
dwcco.print_data()
使用 dir(( 函数获取给定对象的属性,检查它们是否可调用并将它们分配给包装器,如下所示:
class Wrapper:
def wrap_it(self, objToWrap):
for attr in dir(objToWrap):
if not attr.startswith('__') and callable(getattr(objToWrap, attr)):
exec('self.%s = objToWrap.%s' % (attr, attr))
现在,用于测试。
>>> cco = Concrete(5)
>>> wcco = Wrapper()
>>> wcco.wrap_it(cco)
>>> wcco.print_data()
5