Calling methods with an instance of a class as an argument in Python
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 the client to change the state of the instance by specifying the desired target state, after which we run certain validation checks and then the appropriate method. Ideally, I would like the dictionary mapping of the desired target state to the dictionary to follow the correct method to avoid massive and meaningless if-statements. i.e.
if target_state = STARTED:
instance.start()
elif target_state = STOPPED:
instance.stop()
...
But I'm not sure if such a solution is considered good practice or not (it feels like a bit of a strange method to call from a class using an instance as arg).
state_mapping = {
IDLE: StateMachine.reset,
STARTED: StateMachine.start,
....
}
And then calling the use:
action = state_mapping[target_state] action(instance) ....
Any thoughts?
source to share
Not so strange.
However, you only need to consider that action
- this is an unbound method, which may not be very obvious at first sight of the method call; other than that I know firsthand how this vocabulary is defined.
I think a more readable alternative is to call a method from an instance:
state_mapping = {
IDLE: "reset",
STARTED: "start",
....
}
action = state_mapping[target_state]
getattr(instance, action)()
This will also improve readability when the method takes more than one argument.
source to share
Another alternative.
What is your class called "StateMachine", maybe it should have a way to do a state change?
In this case, you can use related methods on the map
class StateMachine:
...
def ChangeState(self, target):
state_mapping = { IDLE: self.reset, STARTED: self.start, ... }
state_mapping[target]()
You can deal with invalid target states, or you can simply let it throw a KEY_ERROR exception.
source to share