Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
263 views
in Technique[技术] by (71.8m points)

design patterns - Stop a python thread from executing and launch a new one

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

[edit: The orginal problem was found by @jaykip. I was passing the wrng object in the Open/Close objects instantiation, now I just want to cancel the opening/closing process with the buttons]

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 buttons, to simulate the open and closed door sensor i just call a sleep function to wait 3 seconds until the door is closed/open.

It 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 doesn't change as it was supposed to. heres the code and a running example:

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


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

    def open(self):
        pass

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


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

    def open(self):
        pass

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


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

    def close(self):
        pass

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


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

    def close(self):
        pass

    def open(self):

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


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()

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

And that is what happens:

<initial state is Open>
Open
<press 'c' key>
Closing...Closed
<wait it finishes and press 'o' key>
Opening...Open
<press 'c' key and while closing press 'o' key>
Closing..Opening...Closed
Open

Any ideas on how to cancel the previous closing Thread so it wont change the state to Clodes and print the "Closed" in the middle of the opening process?


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

It looks like you're passing the Open, etc. objects as the parameter for the next state object. In the close function, it sets self.door.state = Closed(self), where self is the Open object. Closed is looking for an ElevatorDoor object to work. Try self.door instead :) I can't find the pynput module, so I can't test it, but I hope this helps.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...