Python Forum
How to create a variable only for use inside the scope of a while loop?
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
How to create a variable only for use inside the scope of a while loop?
#1
This should be a very basic question.

The code I'm using right now is:
timeOut = 0
while not x == 5:
    time.sleep(1)
    timeOut += 1
    if timeOut > 120:
        exit()
which gets the job done, but I don't like having to create the variable timeOut in the higher scope, as I will be implementing this same exact loop many times, and having to constantly reset the timeOut variable to 0. What is the best way to do this?

Extra nonsense:
I considered using a for loop, but it doesn't seem to be a good option in Python. In C++ a for loop looks something like:
for (int i = 0; i < 5; i++){...}
which essentially works by declaring the variable i, looping until the condition (i < 5) is satisfied, and incrementing i by 1 each time it loops.
The point being that i only exists within this for loop.

In Python for loops iterate through objects or a certain number range, but don't seem to wait until a condition is satisfied. and while loops don't seem to be able to declare variables inside of them (that will only be used in that scope). So I'm not really sure how to go about solving this. (Yes, I am a beginner)
Reply
#2
Close as I could come to it would be something like
n=0
while(n := n + 1) < 5:
    print(n)
    if n == 3:
        n=0
        break
    
    
print(f'out {n}')
Still need to define the variable. Reset it when the condition is met
I welcome all feedback.
The only dumb question, is one that doesn't get asked.
My Github
How to post code using bbtags


Reply
#3
To break out of a while loop use break.

You have no relation between timeOut and x, so what is the point of the while loop?

x = 0
while True:
    x = x + 1    
    if x > 120:
        print('Shit! x got too big!')
        break
menator01 likes this post
Reply
#4
Yeah I was trying to avoid what you did there. (creating the variable at the global scope). I never found a way, but I found a "workaround" per-se, by putting it inside of a function. That way the variable's scope is only that of the function.

And I only used "x == 5" for the sake of simplicity while asking the question. Here is my actual code: (for context, it has just loaded up a webpage, and is waiting for the webpage to load, constantly checking if it is loaded yet.)
pag = pyautogui
def waitToLoad(waitTime: int, checkInterval: float, endBuffer: float, waitLocation, colour):
    pag.moveTo(waitLocation['x'],waitLocation['y']) #move the cursor here, then wait. so it can check the pixel colour
    p = pag.position()
    pag.screenshot() #have to screenshot right now just so the while loop won't throw an error, or accidentally match with the previous screenshot
    timeOut = 0
    while not (pag.pixelMatchesColor(p[0], p[1], colour)): #x value is 0, y value is 1
        #keeps checking the screen every x seconds to see if the cursor's position is on an orange pixel. once it is, it breaks the while loop and clicks. Lets the webpage load.
        time.sleep(checkInterval)
        pag.screenshot()
        timeOut += 1
        if timeOut > waitTime/checkInterval: #60/0.5 = 120. so after 120 loops, 60 seconds would have passed.
            #should send an error report to myself. maybe it requires re-verifying my device or something
            exit() #after this much waiting, you know something has gone wrong
    time.sleep(endBuffer + (endBuffer/10) * (timeOut*checkInterval)) #adds very slight extra delay depending on how long it took to load.
Reply
#5
I don't understand why you are pyautogui.move_to() or pyautogui.screenshot(). pyautogui.pixelMatchesColor() gets the pixel at the screen coordinates provided and compares the color of the pixel to the provided color.

I would write your code like this:
def wait_to_load(coords, color, timeout=1.0, period=0.1, extra_delay=0.1):
    for _ in range(int(timeout / period)):
        time.sleep(period)
        if pyautogui.pixelMatchesColor(*coords, color):
            time.sleep(extra_delay)
            return True
    return False
Loop until the timeout expires or pixel(coords) colour matches colour. No need to make a loop variable at all.

You may notice I removed the exit() and replaced it with a wait status. If wait_to_load() returns True, the page was loaded. If it returns False, the page was not loaded. I would never put exit() inside a function.

All exit() does is raise a SystemExit exception. If you want your function to raise an exception you should define your own.
class PageLoadTimeout(Exception):
    """Exception for when loading a web page times out."""

def wait_to_load(coords, color, timeout=1.0, period=0.1, extra_delay=0):
    for _ in range(int(timeout / period)):
        time.sleep(period)
        if pyautogui.pixelMatchesColor(*coords, color):
            time.sleep(extra_delay)
    else:
        raise PageLoadTimeout
Radical likes this post
Reply
#6
Using time.sleep() for waiting is a simple method but not the best way,
especially in situations where you need your application to remain responsive.
It's a blocking operation for the execution of your program,it will work better with short sleep as deanhysta use.

One with asyncio,i have testet code with color RGB (255, 165, 0) drag into right location to make sure it work.
import pyautogui as pag
import asyncio

async def wait_to_load(wait_time, check_interval, end_buffer, wait_location, colour):
    start_time = asyncio.get_running_loop().time()
    while not pag.pixelMatchesColor(wait_location['x'], wait_location['y'], colour):
        if (current_time := asyncio.get_running_loop().time()) - start_time > wait_time:
            raise TimeoutError(f"Timed out after waiting for {wait_time} seconds.")
        await asyncio.sleep(check_interval)
    load_duration = asyncio.get_running_loop().time() - start_time
    await asyncio.sleep(end_buffer) # Non-blocking sleep
    return load_duration

async def main():
    try:
        duration = await wait_to_load(60, 0.5, 1, {'x': 100, 'y': 200}, (255, 165, 0))
        print(f'Found color( after {duration:.2f} seconds')
    except TimeoutError as e:
        print(e)

asyncio.run(main())
Output:
G:\div_code\ur_env λ python py_ani.py Found color after 4.67 seconds
Radical likes this post
Reply
#7
The dreaded "async virus". Use it once in your code and it spreads uncontrolled. Before you know it all your functions are async.
Reply
#8
(Nov-06-2023, 05:19 PM)deanhystad Wrote: The dreaded "async virus". Use it once in your code and it spreads uncontrolled. Before you know it all your functions are async.
Yes can be downside that all has to async🧬 for it work.
I haven't used asyncio much,so this is more training to see how can work in different scenarios.
I did write one with threading first.
Reply
#9
(Nov-06-2023, 04:03 AM)deanhystad Wrote: I don't understand why you are pyautogui.move_to() or pyautogui.screenshot(). pyautogui.pixelMatchesColor() gets the pixel at the screen coordinates provided and compares the color of the pixel to the provided color.

I would write your code like this:
def wait_to_load(coords, color, timeout=1.0, period=0.1, extra_delay=0.1):
    for _ in range(int(timeout / period)):
        time.sleep(period)
        if pyautogui.pixelMatchesColor(*coords, color):
            time.sleep(extra_delay)
            return True
    return False
Loop until the timeout expires or pixel(coords) colour matches colour. No need to make a loop variable at all.

WHAAAAAAAAT?? You're totally right. For some reason I thought I had to locate the pixel in a screenshot, but I guess not. And I was moving the cursor because that's how I have the rest of my program set up (just capturing the pixel my cursor is hovering over) but there's no reason to do that for this function as well.

What is the * doing in the line "if pyautogui.pixelMatchesColor(*coords, color)"? I tried it out and it does indeed work as intended (if I change my data from a dictionary to a tuple), but I can't seem to find a google result that explains the full usage.

I was mostly asking the question about avoiding the global variable just for the sake of knowledge, but your workaround was quite smart. I'll try it out. Thanks for all the help.
Reply
#10
To create a variable that is only accessible within the scope of a while loop in a programming language like Python, you can declare the variable within the loop itself. This way, the variable's scope is limited to the block of code defined by the loop. Here's an example:


python
Copy code
while condition:
loop_variable = 42 # Declare and initialize a variable inside the loop
# Perform some operations using loop_variable
# The loop_variable is only accessible within this while loop

# The loop_variable is not accessible here and will raise an error if you try to access it
In this code snippet, loop_variable is only accessible within the while loop's scope, and you won't be able to access it outside of the loop.

Keep in mind that the scope of the variable is limited to the block where it is defined. If you need to use the variable's value outside of the loop, you should declare it before the loop and update its value within the loop.
buran write Nov-07-2023, 09:44 AM:
Links removed

Please, use proper tags when post code, traceback, output, etc.
See BBcode help for more info.
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  Variable definitions inside loop / could be better? gugarciap 2 447 Jan-09-2024, 11:11 PM
Last Post: deanhystad
  Possible to create an object inside another object that is visible outside that objec MeghansUncle2 17 2,259 May-25-2023, 02:08 PM
Last Post: MeghansUncle2
  Library scope mike_zah 2 849 Feb-23-2023, 12:20 AM
Last Post: mike_zah
  Help adding a loop inside a loop Extra 31 4,585 Oct-23-2022, 12:16 AM
Last Post: Extra
  Nested for loops - help with iterating a variable outside of the main loop dm222 4 1,605 Aug-17-2022, 10:17 PM
Last Post: deanhystad
  loop (create variable where name is dependent on another variable) brianhclo 1 1,147 Aug-05-2022, 07:46 AM
Last Post: bowlofred
  Multiple Loop Statements in a Variable Dexty 1 1,211 May-23-2022, 08:53 AM
Last Post: bowlofred
  Cursor Variable inside Another Cursor . CX_ORacle paulo79 1 1,530 Apr-09-2022, 10:24 AM
Last Post: ibreeden
Big Grin Variable flag vs code outside of for loop?(Disregard) cubangt 2 1,188 Mar-16-2022, 08:54 PM
Last Post: cubangt
  How to save specific variable in for loop in to the database? ilknurg 1 1,157 Mar-09-2022, 10:32 PM
Last Post: cubangt

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020