包装同类Python对象

Tin*_*rus 9 python

我正在寻找一种方法来收集同类对象,将它们包装在另一个对象中,但使包装对象具有与原始对象相同的API,并将相应的API调用转发给其对象成员。

class OriginalApi:
  def __init__(self):
    self.a = 1
    self.b = "bee"

  def do_something(self, new_a, new_b, put_them_together=None):
    self.a = new_a or self.a
    self.b = new_b or self.b

    if put_them_together is not None:
      self.b = "{}{}".format(self.a, self.b)

  # etc.

class WrappedApi:
  def __init__(self):
    self.example_1 = OriginalApi()
    self.example_2 = OriginalApi()
Run Code Online (Sandbox Code Playgroud)

已经考虑了一些可能的解决方案,但是这些解决方案还不够充分:

  • 重写整个API,为什么不呢?由于API相当大且正在扩展,因此还不够。必须在多个位置维护API是不现实的。

    代码示例:

    class WrappedApi:
      def __init__(self):
        self.example_1 = OriginalApi()
        self.example_2 = OriginalApi()
    
      def do_something(self, new_a, new_b, put_them_together=None):
        self.example_1.do_something(new_a, new_b, put_them_together)
        self.example_2.do_something(new_a, new_b, put_them_together)
    
    Run Code Online (Sandbox Code Playgroud)
  • 使用列表和for循环这将更改对象上的API。就是说,这是我无法找到更优雅的解决方案。在这种情况下,WrappedApi该类将不存在。

    代码示例:

    wrapped_apis = [OriginalApi(), OriginalApi()]
    for wrapped_api in wrapped_apis:
      wrapped_api.do_something(1, 2, True)
    
    Run Code Online (Sandbox Code Playgroud)
  • 我尝试使用 Python Object Wrapper,但是看不到如何用相同的参数调用多个子对象。

对于对用例感到好奇的人,它实际上是几个matplotlib axes对象的集合。我不想重新实现对整个axesAPI(它的大),我不想改变这一切,使中轴线上调用的代码(如plotstep等)

650*_*502 6

如果您仅实现方法,那么泛型__getattr__就可以解决问题

class Wrapper: 
    def __init__(self, x): 
        self.x = x 
    def __getattr__(self, name): 
        def f(*args, **kwargs): 
            for y in self.x: 
                getattr(y, name)(*args, **kwargs) 
        return f
Run Code Online (Sandbox Code Playgroud)

例如,x = Wrapper([[], [], []])调用后,x.append(12)所有三个列表对象的最后一个元素将为12。

请注意,返回值将始终为None...一个选项可以收集返回值并将其作为列表返回,但这当然会“破坏API”。