python class 是否有将其实现委托给另一个 class 的模式?

Is there a pattern for a python class to delegate its implementation to another class?

对于这可能是一个基本问题,我深表歉意。我是一名 C++ 程序员,对 python 比较陌生。

我有一个 python class 其行为在很大程度上取决于其构造函数参数之一:

    class MyClass():
       def __init__(self, some_arg):
          self.some_arg = some_arg
          ...

       def abcd(self):
          if self.some_arg == 1:
             ...
          else:
             ...

       def efgh(self):
          if self.some_arg == 1:
             ...
          else:
             ...

我想将其重构为两个具有不同 some_arg 值的 classes。当然,最直接的方法是拥有两个 classes(可能有一个共同的基础 class),然后让工厂函数选择要实例化的那个。大致如下:

   def MyClassSomeArg1():
      def __init__(self):
         ...

      def abcd(self):
         ...

      def efgh(self):
         ...

   def MyClassSomeArgNot1():
      def __init__(self):
         ...

      def abcd(self):
         ...

      def efgh(self):
         ...

   def buildMyClass(some_arg):
      if some_arg == 1:
        return MyClassSomeArg1()
      else:
        return MyClassSomeArgNot1()

我相信那会很好。问题是我不想更改客户端代码。客户期望使用 some_arg 的构造函数参数实例化 class "MyClass" 的对象。有没有一种不错的方法可以在不更改客户端代码的情况下重构它?

我已经尝试使用一个实现层次结构:MyClassImpl 作为基础 class 与 subclasses MyClassImplSomeArg1 和 MyClassImplSomeArgNot1。然后 MyClass 本身大部分变成空的:

class MyClass():

   def __init__(self, some_arg):
      if some_arg == 1:
         self._impl = MyClassImplSomeArg1()
      else:
         self._impl = MyClassImplSomeArgNone1()

   def __getattr__(self, a):
      # For performance, I could store this in self so it doesn't need to be looked up each time
      return getattr(self._impl, a)

这基本上行得通,但似乎不是最直接的事情。一方面,像 __str__ 和 __eq__ 这样的魔术方法似乎没有通过 __getattr__ 机制进行委托,我不知道为什么。不过,自己编写委托方法并不困难。此外,这会使 pydoc 感到困惑(它无法查看委托属性),我不确定如何解决这个问题。

是否有一些糖分可以使这个授权计划很好地工作?还是授权甚至是处理此类问题的最佳方式?

谢谢,

您可以覆盖 __new__ 函数和 return 基于 some_arg 的子类。这是实现 factory

的常见模式
class MyClassImplSomeArg1:
    pass

class MyClassImplSomeArgNone1:
    pass

class MyClass:
    def __new__(cls, some_arg):
        if some_arg:
            return MyClassImplSomeArg1()
        else:
            return MyClassImplSomeArgNone1()

assert isinstance(MyClass(some_arg=True), (MyClassImplSomeArg1,))
assert isinstance(MyClass(some_arg=False), (MyClassImplSomeArgNone1,))