# Can't get while loop to stop

**URL:** https://discuss.python.org/t/cant-get-while-loop-to-stop/52737
**Category:** Python Help
**Tags:** help
**Created:** [May 6, 2024, 1:54pm UTC](https://discuss.python.org/t/cant-get-while-loop-to-stop/52737 "2024-05-06T13:54:09Z")
**Posts on this page:** 12
**Page:** 1

<div class="post-metadata">

### Author: ![adamwellerfahy](https://avatars.discourse-cdn.com/v4/letter/a/e47c2d/32.png) [@adamwellerfahy](https://discuss.python.org/u/adamwellerfahy)
#### Post date: [May 6, 2024, 1:54pm UTC](https://discuss.python.org/t/cant-get-while-loop-to-stop/52737/1 "2024-05-06T13:54:09Z")

</div>

I am making a number guessing game, and I have a while loop over the whole thing. The problem is, I can’t get it to stop when I want it to.

```python
import random
import sys
import time
ynChoice = 'x'
global runGTN
runGTN = True

while runGTN == True: #the loop
    typing_speed = 300 #wpm
    def printSlow(*t):
        for l in t:
            sys.stdout.write(l)
            sys.stdout.flush()
            time.sleep(random.random()*10.0/typing_speed)
        print()

    def confirmChoice(ynChoice):
        if ynChoice.lower() == 'yes' or ynChoice.lower() == 'y':
            printSlow('Got it!')
            ynChoice = 'y'
        elif ynChoice.lower() == 'no' or ynChoice.lower() == 'n':
            printSlow('Oh. Ok!')
            ynChoice = 'n'
        else:
            printSlow('I don\'t understand. Please input \"yes\" or \"no\".')

    def askGuessDifficulty():
        printSlow('Alright! I\'ll pick a number from 1 to 100, and you try to guess it!')
        printSlow('''You can do easy mode (E), with infinite guess; normal mode (N), with 10 guesses;
    hard mode (H), with 5 guesses; or custom mode (C), where you pick how many guesses you get!''')
        guessDifficulty = input()
        global guesses
        if guessDifficulty.lower() == 'e':
            guesses = 999
            confirmChoice(input('You want easy mode, right? (Please input \"Yes\" or \"No\")'))
        elif guessDifficulty.lower() == 'n':
            guesses = 10
            confirmChoice(input('You want normal mode, right? (Please input \"Yes\" or \"No\")'))
        elif guessDifficulty.lower() == 'h':
            guesses = 5
            confirmChoice(input('You want hard mode, right? (Please input \"Yes\" or \"No\")'))
        elif guessDifficulty.lower() == 'c':
            confirmChoice(input('You want custom mode, right? (Please input \"Yes\" or \"No\")'))
            guesses = input()
            if guesses.isnumeric() == True:
                printSlow('Ok! You want to have ', guesses, ' guesses, right?')
                confirmChoice(input('(Please input \"yes\" or \"no\")'))
                if ynChoice == 'n':
                    return
            else:
                printSlow('I don\'t understand. Please input a number for the amount of guess that you want.')
        else:
            printSlow('''I don\'t understand. Please input \"E\" for easy mode, \"N\" for
            normal mode, \"H\" for hard mode, and \"C\" for custom mode''')

    def playerGuess():
        playerGuessWin = False
        printSlow('Ok! I\'m thinking of a number from 1 to 100')
        printSlow('You\'ll have ', guesses, ' guesses to get it.')
        printSlow('Go ahead and guess when you\'re ready.')
        min = 1
        max = 100
        playerGuessNum = random.randint(min,max)
        while playerGuessWin == False:
            currentGuess = input()
            if currentGuess.isnumeric() == True and int(currentGuess) <= 100 and int(currentGuess) >= 1:
                printSlow('Your guess is...')
                if currentGuess == playerGuessNum:
                    printSlow('CORRECT!')
                else:
                    printSlow('Not right :(')
            else:
                printSlow('I don\'t understand. Please enter a number from 1 to 100.')

    def guessTheNumberStart():
        printSlow('You want to play Guess The Number, right?')
        confirmChoice(input('(Please input \"yes\" or \"no\")'))
        if ynChoice == 'y':
            printSlow('Alright! Let\'s do it!')
        elif ynChoice == 'n':
            printSlow('Oh. Ok!')
            global runGTN
            runGTN = False #this is where it's supposed to stop the while loop
            return #I tried using "break" but it said that it wasn't inside a loop. It just continues on for some reason.
        printSlow('Do you want to guess my number, or should I guess yours?')
        printSlow('(If you want to guess, input \"I\". If I should guess, input \"U\".)')
        whoGuess = input()
        if whoGuess.lower() == 'i':
            printSlow('Ok, you guess!')
            askGuessDifficulty()
            playerGuess()
        elif whoGuess.lower() == 'u':
            printSlow('Ok, I\'ll guess!')
        else:
            printSlow('I don\'t understand. Please input \"I\" if you should guess and input \"U\" if I should guess.')
    guessTheNumberStart()

```

---

<div class="post-metadata">

### Author: ![onePythonUser](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/onepythonuser/32/19158_2.png) [@onePythonUser](https://discuss.python.org/u/onePythonUser)
#### Post date: [May 6, 2024, 6:00pm UTC](https://discuss.python.org/t/cant-get-while-loop-to-stop/52737/2 "2024-05-06T18:00:42Z")

</div>

Hi,

you need to learn about namespace. The keyword `global` is not used on the top of a module.  
You may delete the following line:

`global runGTN`

It is generally used inside of a function to signify that a particular variable’s scope extends outside of it. Why are you defining the functions inside of a while loop multiple times? You only need to define the functions once and then you may call them as many times depending on program needs/conditions.

I would suggest reviewing your code and determining what it is exactly that you want it to do and in what sequence.

Recommend the following regarding global:

> **[Python Global Keyword (With Examples)](https://www.programiz.com/python-programming/global-keyword)**
>
> In this tutorial, we'll learn about the global keyword with the help of examples.

## Rules of global Keyword

The basic rules for `global` keyword in Python are:

- When we create a variable inside a function, it is local by default.
- When we define a variable outside of a function, it is global by default. You don’t have to use the `global` keyword.
- We use the `global` keyword to read and write a global variable inside a function.
- Use of the `global` keyword outside a function has no effect.

By the way, to answer your post header, to make the while loop to stop, generally a test condition needs to be met. In which case you may use the keyword `break`.

for example:

```python
# Test for a predetermined value
counter = 0

while counter < 5: # it will exit after the value 4
    print('counter = ', counter)
    counter += 1 # increment test variable

```

OR

```python
# Run until a condition has been met:
counter = 0

while True: # it will print values up to 9
    print('counter = ', counter)
    counter += 1 # increment test variable

    if counter == 10:
        break

```

In your code, determine which type is required.

You can, of course, have an infinite loop in your main program file to have your code continuously running.

---

<div class="post-metadata">

### Author: ![MRAB](https://avatars.discourse-cdn.com/v4/letter/m/e9c0ed/32.png) [@MRAB](https://discuss.python.org/u/MRAB)
#### Post date: [May 6, 2024, 6:59pm UTC](https://discuss.python.org/t/cant-get-while-loop-to-stop/52737/3 "2024-05-06T18:59:39Z")

</div>

Look at function `confirmChoice`:

```python
def confirmChoice(ynChoice):
    if ynChoice.lower() == 'yes' or ynChoice.lower() == 'y':
        printSlow('Got it!')
        ynChoice = 'y'
    elif ynChoice.lower() == 'no' or ynChoice.lower() == 'n':
        printSlow('Oh. Ok!')
        ynChoice = 'n'
    else:
        printSlow('I don\'t understand. Please input \"yes\" or \"no\".')

```

It accepts a value that’s passed in as parameter `ynChoice`.

Parameters are local to the function, so binding a new value to it won’t affect any similarly-named variable that’s outside the function.

Therefore, this:

```python
confirmChoice(input('You want easy mode, right? (Please input \"Yes\" or \"No\")'))

```

will ask for input and pass it to `confirmChoice`, which might change what its local name is bound to, then print a mesage, and finally return.

It will have no effect on the value of the global `ynChoice` that exists outside the function.

---

<div class="post-metadata">

### Author: ![adamwellerfahy](https://avatars.discourse-cdn.com/v4/letter/a/e47c2d/32.png) [@adamwellerfahy](https://discuss.python.org/u/adamwellerfahy)
#### Post date: [May 7, 2024, 11:59am UTC](https://discuss.python.org/t/cant-get-while-loop-to-stop/52737/4 "2024-05-07T11:59:42Z")

</div>

Is there a way to make the parameter ynChoice global, or do I have to do it another way?

---

<div class="post-metadata">

### Author: ![onePythonUser](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/onepythonuser/32/19158_2.png) [@onePythonUser](https://discuss.python.org/u/onePythonUser)
#### Post date: [May 7, 2024, 12:09pm UTC](https://discuss.python.org/t/cant-get-while-loop-to-stop/52737/5 "2024-05-07T12:09:15Z")

</div>

It is already global. You have defined it at the top of the module and per the second bullet point above:

- When we define a variable outside of a function, it is global by default. You don’t have to use the `global` keyword.

Here is a simple example. Notice how I have assigned a variable outside of the function yet it is visible to the body of the function.

```python
tester = 10

def some_func(x, y):

    print('Testing a global variable.')

    return tester * x * y

print(some_func(5,6))

```

---

<div class="post-metadata">

### Author: ![c-rob](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/c-rob/32/17261_2.png) [@c-rob](https://discuss.python.org/u/c-rob)
#### Post date: [May 7, 2024, 12:13pm UTC](https://discuss.python.org/t/cant-get-while-loop-to-stop/52737/6 "2024-05-07T12:13:33Z")

</div>

> [@onePythonUser](#):
>
> Why are you defining the functions inside of a while loop multiple times?

Is defining functions inside a WHILE loop, or any loop, best practice? Because it makes it hard to read. I’ve never seen that before.

If defining functions inside a loop is done, does that make the function local to that loop?

---

<div class="post-metadata">

### Author: ![onePythonUser](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/onepythonuser/32/19158_2.png) [@onePythonUser](https://discuss.python.org/u/onePythonUser)
#### Post date: [May 7, 2024, 12:19pm UTC](https://discuss.python.org/t/cant-get-while-loop-to-stop/52737/7 "2024-05-07T12:19:01Z")

</div>

The body inside of a loop should be the code that you are running. It generally isn’t for defining functions. That is kind of like assigning the same value to a variable over and over again.

> [@c-rob](#):
>
> If defining functions inside a loop is done, does that make the function local to that loop?

Here is an example:

```python
while True:

    def some_func(x, y):

        print('The sum is: ', x + y)

    counter += 1
    
    if counter == 4:
        break

some_func(10, 20) # Outside of the loop and accessible

```

The function is accessible outside of the loop even if it is defined inside a loop. The point is that it should not be defined multiple times if it is not being modified in any way let alone multiple functions.  
Not only is that redundant, but it adds latency to your script.

---

<div class="post-metadata">

### Author: ![adamwellerfahy](https://avatars.discourse-cdn.com/v4/letter/a/e47c2d/32.png) [@adamwellerfahy](https://discuss.python.org/u/adamwellerfahy)
#### Post date: [May 7, 2024, 12:26pm UTC](https://discuss.python.org/t/cant-get-while-loop-to-stop/52737/8 "2024-05-07T12:26:20Z")

</div>

Thank you for all the feedback, as I’m very new to programming. I changed my code a little, but I’m getting a syntax error saying that my break is outside of a loop.

```python
def guessTheNumberStart():
    printSlow('You want to play Guess The Number, right?')
    confirmChoice(input('(Please input \"yes\" or \"no\")'))
    if ynChoice == 'y':
        printSlow('Alright! Let\'s do it!')
    elif ynChoice == 'n':
        printSlow('Oh. Ok!')
        break #break, which is inside function, which is inside loop, so why doesn't it work?
    printSlow('Do you want to guess my number, or should I guess yours?')
    printSlow('(If you want to guess, input \"I\". If I should guess, input \"U\".)')
    whoGuess = input()
    if whoGuess.lower() == 'i':
        printSlow('Ok, you guess!')
        askGuessDifficulty()
        playerGuess()
    elif whoGuess.lower() == 'u':
        printSlow('Ok, I\'ll guess!')
    else:
        printSlow('I don\'t understand. Please input \"I\" if you should guess and input \"U\" if I should guess.')
while True: #loop
    guessTheNumberStart()

```

error:

````python
File "/home/adamwellerfahy/minigames.py", line 150
    break
    ^^^^^
SyntaxError: 'break' outside loop
>>> ```
````

---

<div class="post-metadata">

### Author: ![onePythonUser](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/onepythonuser/32/19158_2.png) [@onePythonUser](https://discuss.python.org/u/onePythonUser)
#### Post date: [May 7, 2024, 12:45pm UTC](https://discuss.python.org/t/cant-get-while-loop-to-stop/52737/9 "2024-05-07T12:45:40Z")

</div>

> [@adamwellerfahy](#):
>
> ```python
> elif ynChoice == 'n':
> printSlow('Oh. Ok!')
> break #break, w
> 
> ```

the `break` has to be used in a loop. Here, you are using inside of a conditional statement body.

Loops consists of `while` and `for`

> [@adamwellerfahy](#):
>
> `#break, which is inside function, which is inside loop, so why doesn't it work?`

Its called `scope`. The `break` is local (visible) only to the body of the function and not to the `while` loop in which the function resides.

If you want to jump out of the function for this condition, you can of course instead use:

return None

For example, practice with this test script:

```python
test_value = 2

def some_func(h):

    if h == 2:
        print('h is 2')

    elif h == 4:
        return None

    elif h == 1:
        print('The value is 1.')

    print('The end of the function.')

print('Outside and after function.')

some_func(test_value)

```

---

<div class="post-metadata">

### Author: ![kknechtel](https://avatars.discourse-cdn.com/v4/letter/k/e47c2d/32.png) [@kknechtel](https://discuss.python.org/u/kknechtel)
#### Post date: [May 7, 2024, 5:09pm UTC](https://discuss.python.org/t/cant-get-while-loop-to-stop/52737/10 "2024-05-07T17:09:56Z")

</div>

The code inside a function is compiled once, ahead of time, before anything runs. The `def` statement creates the function object from mostly-pre-made pieces and assigns it to a name. The assignment follows the same scoping rules as any other assignment - loops don’t have their own scope.

There’s generally not a good reason do to this. Sometimes it’s for the purpose of “binding” arguments to a function that will be used as a callback, and making separate versions with differently bound arguments. For example, to handle button clicks in a GUI, binding separate information to each button’s callback, so it can do something appropriate depending on which button was clicked. However, this is trickier than it appears:

> <https://stackoverflow.com/questions/3431676/creating-functions-or-lambdas-in-a-loop-or-comprehension>

> <https://stackoverflow.com/questions/277922/how-can-i-bind-arguments-to-a-function-in-python>

---

<div class="post-metadata">

### Author: ![kknechtel](https://avatars.discourse-cdn.com/v4/letter/k/e47c2d/32.png) [@kknechtel](https://discuss.python.org/u/kknechtel)
#### Post date: [May 7, 2024, 5:23pm UTC](https://discuss.python.org/t/cant-get-while-loop-to-stop/52737/11 "2024-05-07T17:23:15Z")

</div>

> [@adamwellerfahy](#):
>
> ```python
> break #break, which is inside function, which is inside loop, so why doesn't it work?
> 
> ```

“inside” here is **only** talking about **how the code is structured** - not about what happens when you run it. The function is not indented, and doesn’t have the `while` line above it, therefore it isn’t inside the loop.

A function can be called from multiple places - **that’s the point**. Therefore, it doesn’t and shouldn’t normally care about where it was called from, and certainly can’t directly change the control flow of that other code. Instead, a function knows about the _arguments_ that were passed to it (the things you put between `()` when you call it), which it refers to internally via its _parameters_ (the things you put between `()` on the `def` line). That’s the primary way to get information _in_ to the function. To get information _out_, the primary way is to `return` a value. That value represents the result of the function’s calculation. Then the outside code can examine that result to decide what to do.

The way to keep this organized is to make sure that functions have a single, clearly defined role - one thing that they calculate, and one meaning for the result of that calculation.

Try writing a function that _only_ asks the user whether to play, and `return`s a value that indicates the answer. (Hint: what _type_ of value makes sense to answer a yes-or-no question?) Then write another function to find out who should play first. (Hint: if the input here is bad, then we should prompt the user again, right? So, maybe the loop should really be _inside this_ function… ?) _Do not_ move on to `askGuessDifficulty` or `playerGuess` here - those are _not part of how you find out_ who plays first. In the outside code, call those functions to find out the answers, and proceed accordingly.

---

<div class="post-metadata">

### Author: ![cameron](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/cameron/32/2658_2.png) [@cameron](https://discuss.python.org/u/cameron)
#### Post date: [May 8, 2024, 12:55am UTC](https://discuss.python.org/t/cant-get-while-loop-to-stop/52737/12 "2024-05-08T00:55:39Z")

</div>

Although the function is being called inside your `while` loop, the code  
inside the function doesn’t know that.

The body of a function is self contained, and there’s no loop _inside_  
the function. Hence the error - the `break` has no loop to break out of  
there.

If you’re wanting to terminate the `while` loop early, that test needs to  
be in the `while` loop code. Usually we’d examine the return value from  
the function. For example you could have the function return value be  
some kind of “final call” Boolean value - `True` when the caller should  
stop calling the function again, and `False` otherwise.

So the `while` loop might look like this:

```
 while True:
     is_final = guessTheNumberStart()
     if is_final:
         break

```

Here, the `break` is inside the `while` loop’s body.

As an aside, you can simplify this `if` statement:

```
     if guessTheNumberStart():
         break

```

and because the loop itself does nothing but call the function, you can  
write the loop like this:

```
 while not guessTheNumberStart():
     pass

```

i.e. it says “run while guessTheNumberStart(0 returns a false value” aka  
“until the user guesses correctly”.

WRT the function, you’d put a `return False` at the bottom (the default  
result) and a `return True` where you have the current `break`  
statement:

```
 def guessTheNumberStart():
     printSlow('You want to play Guess The Number, right?')
     confirmChoice(input('(Please input \"yes\" or \"no\")'))
     if ynChoice == 'y':
         printSlow('Alright! Let\'s do it!')
     elif ynChoice == 'n':
         printSlow('Oh. Ok!')
         return True
     printSlow('Do you want to guess my number, or should I guess yours?')
     printSlow('(If you want to guess, input \"I\". If I should guess, input \"U\".)')
     whoGuess = input()
     if whoGuess.lower() == 'i':
         printSlow('Ok, you guess!')
         askGuessDifficulty()
         playerGuess()
     elif whoGuess.lower() == 'u':
         printSlow('Ok, I\'ll guess!')
     else:
         printSlow('I don\'t understand. Please input \"I\" if you should guess and input \"U\" if I should guess.')
     return False

```
