这是 Pythonic 吗?动态分配 class 方法

Is this Pythonic? Assigning class methods dynamically

根据对class的输入,需要在一个公共接口下使用不同的方法(这里称为method)。以下哪个更符合 Pythonic?

尝试 #1

class ExampleClass(object):
   def __init__(self, a=None, b=None):
       self.a = a
       self.b = b
       if a is not None:
           self.method = self._a_method
       else:
           self.method = self._b_method

   def method(self):
       raise NotImplementedError

   def _method_a(self):
       return "I am a method that relies on input: " + self.a

   def _method_b(self):
       return "I am a method that relies on input: " + self.b

或尝试#2:

class ExampleClass(object):
    def __init__(self, a=None, b=None):
        self.a = a
        self.b = b

    def method(self):
        if self.a is not None:
           return self._method_a(self)
        else:
           return self._method_b(self)

   def _method_a(self):
       return "I am a method that relies on input: " + self.a

   def _method_b(self):
       return "I am a method that relies on input: " + self.b

在这种情况下可能没有太大关系,但在我的情况下我有不止一个 method,这意味着方法 #2 违反了 DRY 原则(将有相同的 if,else 逻辑在每个 methods).

另一方面,在 __init__ 中动态分配 _method_* 函数是否很尴尬,因为它在尝试 #1 中已关闭?

我会说这两种方法都显示出糟糕的 OOP 设计,我认为应该避免,除非你的整个 ExampleClass API(包括构造函数)已经暴露给客户并且应该按原样保留向后兼容性。如果不是这种情况,我认为 Factory pattern should be used, probably something like "static factory methods" as described at http://www.drdobbs.com/jvm/creating-and-destroying-java-objects-par/208403883 的一些变化。使用这种方法,您可以根据参数轻松创建不同子类型的对象。此外,您可以提供具有不同名称的不同工厂方法,以更好地反映创建对象的含义,而不仅仅是分析参数。

如果您的 API 应该保留并且性能不是至关重要的(并且考虑到您使用 Python,我认为这是理所当然的),我会投票让 ExampleClass一个包装器,它将所有实际工作委托给通过工厂创建的内部委托。像这样:

class ExampleClass(object):
   def __init__(self, a=None, b=None):
       if a is not None:
           self._delegate = ExampleAImpl(a)
       else:
           self._delegate = ExampleBImpl(b)

   def method(self):
       return self._delegate.methodImpl()


class ExampleAImpl(object):
   def __init__(self, a):
       self.a = a

   def methodImpl(self):
       return "I am a method that relies on input: " + self.a

class ExampleBImpl(object):
   def __init__(self, b):
       self.b = b

   def methodImpl(self):
       return "I am a method that relies on input: " + self.b

注意:此方法不适用于从 ExampleClass 继承。此外,如果您需要 ab 仍然是 public 属性,也可以这样做,但会使代码更加复杂。