这是 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 逻辑在每个 method
s).
另一方面,在 __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
继承。此外,如果您需要 a
和 b
仍然是 public 属性,也可以这样做,但会使代码更加复杂。
根据对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 逻辑在每个 method
s).
另一方面,在 __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
继承。此外,如果您需要 a
和 b
仍然是 public 属性,也可以这样做,但会使代码更加复杂。