在Python中,状态对象与无状态计算的分界在哪里?
以下哪个代码片段是最“符合Python风格”的?虽然在这个例子中计算很简单,但在实际生活中可能会很复杂。
class A(object):
"""Freely mix state and calcs - no good I presume"""
def __init__(self, state):
self.state = state
def calc_with_state(self, x):
return (self.state + x)**2
或者
class B(object):
"""Separate state from calc by a static method"""
@staticmethod
def inner_calc(u, v):
return (u + v)**2
def __init__(self, state):
self.state = state
def calc_with_state(self, x):
return B.inner_calc(self.state, x)
或者
class C(object):
"""Break out the calculation in a free function"""
def __init__(self, state):
self.state = state
def calc_with_state(self, x):
return outer_calc(self.state, x)
def outer_calc(u, v):
return (u + v)**2
5 个回答
1
把计算过程单独提出来,无论是用静态方法还是全局方法,其实对“状态意识”没有什么好处。唯一稍微有点好处的是,代码能清楚地显示出在计算中考虑了哪些对象的状态属性(这样在调用函数的时候就能看到,而不需要在类A的方法逻辑里去找)。
不过,使用无状态的方法(静态的、全局的)或者实例方法可能还有其他一些好处:
- 可以重复使用
- 整体上代码更易读和管理
但是,正如前面所说,这些方法对状态管理本身并没有帮助。我觉得A的方法看起来很合理(而且符合Python的风格)。确实,David Berger 早就提醒过我们……
简单比复杂好!
1
我觉得这要看你具体的项目情况。cal_with_state
这个方法是只适用于这个特定的类,还是说这个方法需要在很多不同的对象之间共享?不同的类之间会共享这个方法吗?
这些方法没有哪个更“pythonic”(符合Python风格)的说法,选择一个能满足你项目需求的方法就好。DRY(不要重复自己)是比“pythonic”更重要的原则。
6
简单来说,答案是A,差得远。问题很简单,就是:
简单比复杂好。
你看:把状态和计算分开是个好设计原则,但这并不意味着你想的那样,至少不是我从这个例子中能推测到的。我们要确保状态在进行计算时不会发生变化,前提是这个状态在下一次计算时不会被重新初始化。如果某个计算对状态是只读的,那么就没有必要绕过它,直接去读取它。也就是说,除非计算和状态复杂到需要单独进行单元测试。这样的话,B或C会更受欢迎,但前提是创建u的值真的比重新实例化的实例要简单得多。