'Python exit() command trigger infinite loop

Greeting all, I encountered infinite loop when running the code below when input option = 3.

def enter_number_only():
    print()
    print("======================")
    print("Enter Number 1-3 only!")
    print("======================")
def thank_you_goodbye():
    print()
    print("======================")
    print("Thank You & GoodBye!")
    print("======================")
    exit()
def retry_main_exit():
    while True:
        print("1. Retry")
        print("2. Back to Main Menu")
        print("3. Exit / Quit")
        print("=================================")
        try:
            option = int(input("Please Enter 1 - 3 to Continue: "))
            if option == 1:
                print("1")
                break
            elif option == 2:
                print("2")
                break
            elif option == 3:
                thank_you_goodbye()
                break
            else:
                enter_number_only()
        except:
            enter_number_only()

    return option

retry_main_exit()

However, if I replaced: (initial code)

 elif option == 3:
      thank_you_goodbye()
      break

to (edited code)

 elif option == 3:
      print("gg")
      break

it will exit the loop smoothly.

Need advice on how to remain the initial code but to be able exit the loop? and seeking for the root cause on this issue.

Many thanks in advance.

Updates: The issue get solved by sharing from @Daniel Corin due to except clause. The code get fixed with edit below

except TypeError:
       enter_number_only()


Solution 1:[1]

Just remove exit on last line of thank_you_goodbye function, then it will work smoothly.

def thank_you_goodbye():
    print()
    print("======================")
    print("Thank You & GoodBye!")
    print("======================")
    exit()

Solution 2:[2]

A number of folks have mentioned a fix by removing exit() but let's dive into why you are seeing what you're seeing with a simpler example:

In the following code, we first request user input, then we call exit() which raises SystemExit, which is then handled by the bare except clause.

Side note: using bare except clauses is not recommended. More on that here.

while True:
  try:
    i = input('input? ')
    exit()
  except:
    print('hey')

We might expect after entering the first user input that the program would loop around to ask for user input again after handling SystemExit in the except clause. However, what happens instead is the following:

? python3 test.py
input? 1
hey
input? hey
input? hey
input? hey
input? hey
...infinitely

However, if SystemExit is handled explicitly, the program also does something we might not expect -- it actually exits, raising a different exception:

while True:
  try:
    i = input('input? ')
    exit()
  except SystemExit:
    print('hey')
? python3 test.py
input? 1
hey
input? Traceback (most recent call last):
  File "/Users/danielcorin/Desktop/test.py", line 3, in <module>
    i = input('input? ')
ValueError: I/O operation on closed file.

It turns out that raising SystemExit closes stdin (which is needed by the input function), even if the program itself doesn't exit. So in our first example, after calling exit(), we have a broken input function, which raises a ValueError on the second-N calls.

Example exit() closing stdin:

import sys

try:
  print(sys.stdin.isatty())
  exit()
except SystemExit:
  print(sys.stdin.isatty())

? python3 test2.py
True
Traceback (most recent call last):
  File "/Users/danielcorin/Desktop/test2.py", line 5, in <module>
    exit()
  File "/usr/local/Cellar/[email protected]/3.9.1_1/Frameworks/Python.framework/Versions/3.9/lib/python3.9/_sitebuiltins.py", line 26, in __call__
    raise SystemExit(code)
SystemExit: None

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/Users/danielcorin/Desktop/test2.py", line 7, in <module>
    print(sys.stdin.isatty())
ValueError: I/O operation on closed file

We're still in the while loop, so all exceptions (first SystemExit and then ValueError repeatedly) are handled by the bare except clause, so the result is the program prints forever, until we signal our program externally to terminate it. This behavior is the same exhibited by your program when exit() is called in the thank_you_goodbye function.

In short, the exit() call breaks the input function which leads to an infinite loop due to the bare except clause.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Nagmat
Solution 2 Daniel Corin