Infinite loop 'try and if' under a method

478 views Asked by At
  1. Executing menu() and go to 1 or 2 or 3 is good to do its work.

  2. But after passing by getproduct(character) and getting back to menu() and then if you choose number 3, it makes a bad loop.

I want to know why, and how to solve this problem...

def menu():

    menu = '1. ice\n2. cream\n3. quit'
    print(menu)
    
    try:
        order = int(input('choose one: '))
        
        if order == 1:
            c = 'ice'
            getproduct(c)
        elif order == 2:
            c = 'cream'
            getproduct(c)
            
        elif order == 3:
            exit()
            
        else: menu()
        
    except ValueError: menu()


def getproduct(character):

    toping = int(input('1. ice or 2. cream?'))
    
    try:
        if character == 'ice' and toping == 1:
            print(character + 'ice')
            menu()
        
        elif character == 'ice' and toping == 2:
            print(character + 'cream')
            menu()
        elif character == 'cream' and toping == 1:
            print(character + 'ice')
            menu()
        elif character == 'cream' and toping == 2:
            print(character + 'cream')
            menu()
        else: getproduct(character)
    except: getproduct(character)
    
        
menu()
2

There are 2 answers

3
Getsuryu On BEST ANSWER

There are several mistakes on the code. First of all, you are using exit, that should not be used within files, instead of it, I use on my example the module sys (sys.exit(0)) that has the same goal.

On the other hand, you are using the input checks in an imprecise way, and looping should be different. In menus, I personally recommend using while loops.

Solution for your problem and a a couple of improvements (could be better):

import sys

def menu():
    menu = '1. ice\n2. cream\n3. quit'

    while True:
        print(menu)
        try:
            order = int(input('choose one: '))
        except:
            print("Use a correct answer")
        else:
            if order == 1:
                c = 'ice'
                getproduct(c)
            elif order == 2:
                c = 'cream'
                getproduct(c)
            elif order == 3:
                sys.exit(0)
            else:
                print("Use a correct answer")

def getproduct(character):
    topings = '1. ice or 2. cream?: '

    while True:
        print(topings)
        try:
            second_order = int(input())
        except:
            print("Use a correct answer")
        else:
            if character == 'ice' and second_order == 1:
                print(character + 'ice')
                break
            elif character == 'ice' and second_order == 2:
                print(character + 'cream')
                break
            elif character == 'cream' and second_order == 1:
                print(character + 'ice')
                break
            elif character == 'cream' and second_order == 2:
                print(character + 'cream')
                break
            else:
                print("Use a correct answer.")

menu()
0
Green Cloak Guy On

The exit() function works by raising the SystemExit type of exception, which propagates up the chain until there's nothing more to run and the program comes to a stop.

That it is an exception means that the code above where the SystemExit is raised is allowed to close resources and do other wind-down activities, so as not to break any external resources. However, it also means that a blank except: statement can catch the SystemExit and ignore it. Which is what's happening here.

def getproduct(character):

    toping = int(input('1. ice or 2. cream?'))
    
    try:
        ...
        # call to menu(), which calls exit()
    except: # this activates on ANY exception, including SystemExit
        getproduct(character)

In general, you should almost never use a raw except block, because of situations like this where it catches something you don't want it to. Instead, analyze the code inside the try, figure out what types of exceptions it would throw, and catch those. In your case, it's likely to be either ValueError or TypeError:

try:
    ...
except (ValueError, TypeError):
    getproduct(character)

or, if you're dead set on catching everything, you can write a special exception for if the error is a SystemExit (though, again, a blank except: or a except Exception: is considered bad practice):

try:
    ...
except SystemExit:
    pass  # ignore it
except:
    getproduct(character)

You should note, according to the documentation:

quit(code=None) exit(code=None) Objects that when printed, print a message like “Use quit() or Ctrl-D (i.e. EOF) to exit”, and when called, raise SystemExit with the specified exit code.

You should probably use sys.exit() instead, though it does basically the same thing.