1

I have a while loop that is reading user input. But I want the user to be able to break the while loop at any point, so they can go back to a main menu.

At the moment this is the only way I can do it (if statements after every point that the user may have typed '--back'. The menu.code is returned from the menu.parse function if it is changed. But then the while loop has to completely finish before it's new menu code takes effect. Is there a way of doing this without all the if statements?

menu is a class, and there are a couple of others. Below is a section from the main loop.

Some of the menu class:

class Menu:

    def __init__(self):
                self.code = 'main'
                self.codememory = []

    def exit(self, input):
        if input == '--exit':
            sys.exit()

    def back(self, input):
        if input == '--back':
            if 'main' in self.codememory:
                print "should be going back"
                print self.code
                self.code = self.codememory.pop()
                print self.code

    def move(self, input):
        if input == '--new':
            self.codememory.append(self.code)
            self.code = 'new'
        if input == '--main':
            self.codememory.append(self.code)
            self.code = 'main'
        if input == '--help':
            self.codememory.append(self.code)
            self.code = 'help'

    def select(self, input):
        if input in string.digits:
            input = int(input)
            if input == 1:
                self.codememory.append(self.code)
                self.code = 'new'
            if input == 2:
                self.codememory.append(self.code)
                self.code = 'test'

    def header(self, title):
        os.system('clear')
        print "-------------------"
        print title.upper()
        print "-------------------"
        print ""

    def parse(self, input):
        self.exit(input)
        self.back(input)
        if self.code == 'new':
            return input.lower().decode('utf-8')

############################
   menu = Menu()



        while 1:

            ...

            while menu.code == 'new':
                    menu.header('save word')
                    key = menu.parse(raw_input("Norwegain: "))
                    while key in dict.keys:
                        print "word already Saved in Dictionary"
                        key = menu.parse(raw_input("Norwegain: "))
                    if menu.code == 'new':
                        val = menu.parse(raw_input("English: "))
                    if menu.code == 'new':
                        syn = menu.parse(raw_input("Synonym: "))
                    if menu.code == 'new':
                        ant = menu.parse(raw_input("Antonym: "))

            while menu.code == 'main':
                    ...
9
  • The code for your menu class would be great, because we wouldn't have to guess what it does, and we can give a solution we know should work. Commented Mar 8, 2012 at 22:30
  • i'll add it. Please be gentle... I'm learning! Commented Mar 8, 2012 at 22:35
  • stackoverflow.com/questions/189645/… Commented Mar 8, 2012 at 22:35
  • I don't understand why the "if menu.code == 'new':" is repeated. Is that a typo? Can menu.code change between the start of the while loop and the if statements? Can menu.parse change menu.code? Commented Mar 8, 2012 at 22:37
  • I don't understand why the "if menu.code == 'new':" is repeated. Is that a typo? Can menu.code change between the start of the while loop and the if statements? Can menu.parse change menu.code? If the answer to these is "Yes", I think you have a more significant structural problem that will make your code very hard to maintain. Commented Mar 8, 2012 at 22:38

3 Answers 3

3

To break out of multiple loops in Python, wrap the loops in a function and return from it when you would like to leave:

while 1:
    def donew():
       while menu.code == 'new':
          blah ...
          while key in dict.keys:
             blah ...
             if some_condition: return
          blah ...
          val = menu.parse(raw_input("English: "))
    donew()
Sign up to request clarification or add additional context in comments.

1 Comment

Ah, I thought return was for returning values. I didn't know I could return 'out' of something.
1

With this particular code, @kriss' suggestion to use exceptions is probably reasonable. Going a little more meta, you may want to look into state machines, though. It looks like your application is essentially a state machine, and, by using a state machine to handle transitions from one state to another, you could make your code much easier to follow and, more importantly, much easier to come back to in six months when somebody wants to add another command to it.

1 Comment

Thanks... I will. can I find info on python.org? had a quick look in documentation...
1

Raise an exception to exit the loop. This is a common enough trick in Python and the way you describe your problem makes me believe it is actually some kind of exception you are willing to manage.

Code may look like below:

class OutMainLoop(Exception):
    pass

while 1:
    try:
       while menu.code == 'new':
          blah ...
          while key in dict.keys:
             blah ...
             if some_condition:
                raise OutToMainLoop()
          blah ...
          val = menu.parse(raw_input("English: "))
    except OutToMainLoop:
        pass

But in this case it would certainly be even more natural to raise the exception from inside the menu class.

It very easy to do in Python. The Drawback is that is makes the code flow slightly harder to follow, but your example really looks like a legitimate use of an Exception.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.