2017-06-20 45 views
3

假设我有以下代码与类实例调用方法的参数在Python

IDLE = 0 
STARTED = 1 
STOPPED = 2 
ERRORED = 3 
# additional states as needed 

class StateMachine: 
    def __init__(self) 
     self.state = IDLE 

    def start(self): 
     self.state = STARTED 
     # do something 

    def stop(self): 
     self.state = STOPPED 
     # do something 

    def reset(self): 
     self.state = IDLE 
     # do something 

我们目前的接口允许客户端通过阐明期望的目标状态改变实例的状态,在这一点上,我们运行某些验证检查以及适当的方法。理想情况下,我希望保持所需目标状态的字典映射到正确的方法,以避免大量和无意义的if语句块。即

if target_state = STARTED: 
    instance.start() 
elif target_state = STOPPED: 
    instance.stop() 
... 

但我不确定下面的解决方案是否被认为是好的做法或不(它使用的实例作为ARG感觉从类有点怪的调用方法)。

state_mapping = { 
    IDLE: StateMachine.reset, 
    STARTED: StateMachine.start, 
    .... 
} 

,然后调用使用:

action = state_mapping[target_state] 
action(instance) 
.... 

有什么想法?

+0

您是否尝试过使用'lambda'表达式? –

+0

我认为解决方案是可以的。也许你应该考虑基准测试,看看什么时间更有效率。如果效率不是问题,可读性应该是。我个人认为'如果'elif'' elif''else'解决方案更具可读性 - 即使它有点无聊。 – ChickenFeet

+0

还有另一种方法,它有一个整体StateMachine类,然后是每个状态的子类,如StateMachineStopped,StateMachineStarted。你用'self .__ class__ = StateMachineStopped'方法来回切换。例如,请参阅https://stackoverflow.com/questions/13280680/how-dangerous-is-setting-self-class-to-something-else/24463654#24463654。 –

回答

2

不那么怪异。

但是,唯一需要牢记的是action是一个未绑定的方法,在对方法调用进行初看时可能不是很明显;除非我直接知道该字典是如何定义的。

我觉得更可读的替代方法是从实例调用方法:

state_mapping = { 
    IDLE: "reset", 
    STARTED: "start", 
    .... 
} 

action = state_mapping[target_state] 
getattr(instance, action)() 

这同样会提高可读性的情况下,当方法需要多个参数。

+0

感谢您的反馈意见,我曾考虑过这样做,但在两种方法之间有点分裂。现在你提到了可读性,用getattr代替它是有道理的。 – Andy

1

另一种选择。

由于你的类被称为“StateMachine”,也许它应该有一个方法来执行状态改变?

在这种情况下,您可以使用绑定方法在地图

class StateMachine: 
    ... 

    def ChangeState(self, target): 
     state_mapping = { IDLE: self.reset, STARTED: self.start, ... } 
     state_mapping[target]() 

您可能希望处理无效的目标状态,还是让它养KEY_ERROR例外。

相关问题