Reputation: 33
Assuming I have the following code
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
Our current interface allows a client to change the state of an instance by stating the desired target state, at which point we run certain validation checks and then the appropriate method. I would ideally like to keep a dictionary mapping of the desired target state to the correct method to avoid massive and pointless if-statement blocks. i.e.
if target_state = STARTED:
instance.start()
elif target_state = STOPPED:
instance.stop()
...
But I'm uncertain as to whether or not the following solution is considered good practice or not (it feels a bit whacky calling methods from the class using an instance as arg).
state_mapping = {
IDLE: StateMachine.reset,
STARTED: StateMachine.start,
....
}
And then calling using:
action = state_mapping[target_state]
action(instance)
....
Any thoughts?
Upvotes: 3
Views: 105
Reputation: 8215
One other alternative.
As your class is called "StateMachine", perhaps it should have a method to execute the state change?
In which case, you can use bound methods in your map
class StateMachine:
...
def ChangeState(self, target):
state_mapping = { IDLE: self.reset, STARTED: self.start, ... }
state_mapping[target]()
You may want to deal with invalid target states, or just let it raise a KEY_ERROR exception.
Upvotes: 1
Reputation: 78554
Not so whacky.
However, the only thing one has to bear in mind is that action
is an unbound method, which may not be very obvious at a first glance of the method call; except I know first-hand how that dictionary is defined.
I think a more readable alternative is to call the method from the instance:
state_mapping = {
IDLE: "reset",
STARTED: "start",
....
}
action = state_mapping[target_state]
getattr(instance, action)()
This will equally improve readability in the case when the method takes more than one argument.
Upvotes: 2