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?

+3


source to share


2 answers


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.

+2


source


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.

+1


source







All Articles