mardi 5 janvier 2021

Python threaded method is not changing object state

I'm currently studying some Design Patterns in Python and tried to implement the State Patter example in the diagram:

State diagram for elevator door

It happened to be way more complicated than I expected, I've created a class for each of the four states and the open and close methods. To simulate the Open and Close Buttons I uused th pynput module so I can listen to the keyboard and call the open and close and to simulate the open and closed door sensor i just call a sleep function to wait 3 seconds until the door is closed/open.

I was working ok until i decided to use Threads so the sleep function call does not block the main program and I could "press button" while the door is closing/opening. Now the state doen't change as it was supposed to. heres the code and an runnong example:

from time import sleep
from pynput import keyboard
from threading import Thread


class Open():
    def __init__(self, door):
        self.door = door

    def __repr__(self):
        return 'Open'

    def open(self):
        pass

    def close(self):
        print('Closing', end='')
        self.door.state = Closing(self)
        for _ in range(3):
            print('.', end='', flush=True)
            sleep(1)
        self.door.state = Closed(self)
        print('Closed')


class Opening():
    def __init__(self, door):
        self.door = door

    def __repr__(self):
        return 'Opening'

    def open(self):
        pass

    def close(self):
        print('Opening Interrupted')
        self.door.state = Closing(self)
        print('Closing', end='')
        for _ in range(3):
            print('.', end='', flush=True)
            sleep(1)
        self.door.state = Closed(self)
        print('Closed')


class Closed():
    def __init__(self, door):
        self.door = door

    def __repr__(self):
        return 'Closed'

    def close(self):
        pass

    def open(self):
        print('Openning', end='')
        self.door.state = Opening(self)
        for _ in range(3):
            print('.', end='', flush=True)
            sleep(1)
        self.door.state = Open(self)
        print('Open')


class Closing():
    def __init__(self, door):
        self.door = door

    def __repr__(self):
        return 'Closing'

    def close(self):
        pass

    def open(self):
        print('Closing Interrupted')
        print('Openning', end='')
        self.door.state = Opening(self)
        for _ in range(3):
            print('.', end='', flush=True)
            sleep(1)
        self.door.state = Open(self)
        print('Open')


class ElevatorDoor:
    def __init__(self):
        self.state = Open(self)

    def open(self):
        Thread(target=self.state.open).start()

    def close(self):
        Thread(target=self.state.close).start()


if __name__ == '__main__':
    door = ElevatorDoor()

    def on_press(key):
        global door
        if key == keyboard.Key.esc:
            return False  # stop listener
        try:
            k = key.char  # single-char keys
        except Exception:
            k = key.name  # other keys

        if k == 'o':
            door.open()
        if k == 'c':
            door.close()
        if k == 's':
            print(door.state)

    listener = keyboard.Listener(on_press=on_press)
    listener.start()
    listener.join()

And that is what happens:

<starts script>
<press 'c' key>
Closing...Closed
<press 's' key to check the state>
Closed
<press 'o' key>
Openning...Open
<press 's' key>
Closed
<press 'c' key>
<Nothing happens>
<press 'o' key>
Openning...Open

Any Ideas of what can be going On? Any simpler ways to implement this also are welcome :)

Aucun commentaire:

Enregistrer un commentaire