Python中的动态包装器

时间:2018-04-11 12:20:50

标签: python python-3.x

我正在寻找创建一个动态包装类,它使用对象中的数据公开来自提供对象的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,但我没见过 关于如何将所有这些放在一起的例子。

2 个答案:

答案 0 :(得分:3)

您可以使用__getattr__魔术方法来挂钩获取未定义的属性,并将它们转发到具体对象:

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()

答案 1 :(得分:1)

使用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