While function stuck on first block of if-elif-else - python

I'm trying to code a small pomodoro-timer, it uses a while loop with an if-elif-else statement to check which timer to start.
As expected it starts with the first if-block and then modifies the variable, I would expect it to go the elif-block after that, however it seems to be stuck in the if-block. And doesn't reiterate the entire while loop code.
How to overcome this?
import os
import time
pomodoro = ['Pomodoro', 1500]
short_break = ['Short Break', 300]
long_break = ['Long Break', 1800]
pomodori_count = 0
def countdown(time_frame):
duration = time_frame[1]
while duration:
os.system('clear')
mins, secs = divmod(duration, 60)
timer = '{:02d}:{:02d}'.format(mins, secs)
print(f"{time_frame[0]} | {timer}")
time.sleep(1)
duration -= 1
while True:
last = ""
if last != "Pomodoro":
countdown(pomodoro)
last = "Pomodoro"
pomodori_count += 1
elif pomodori_count % 4 != 0:
countdown(short_break)
last = "Short Break"
else:
countdown(long_break)
last = "Long Break"

So what is wrong with this code is that you reset the last value in each repeat of the while loop, so it never persists its state for the next cycle.
You should declare the variable before the while loop to fix this issue
last = ""
while True:
if last != "Pomodoro":
countdown(pomodoro)
last = "Pomodoro"
pomodori_count += 1
elif pomodori_count % 4 != 0:
countdown(short_break)
last = "Short Break"
else:
countdown(long_break)
last = "Long Break"

Related

Threading in Python with Timed While Loop

A similar question was asked earlier but it didn't provide the correct answer.
I am trying to code to test threading in Python in which a ticker ticks every second. I am trying to keep the ticker function named 'clicking' running in a thread whose output is continously being incremented by one every second.
import time
import threading
import queue
q = queue.Queue()
apple = 0
orange = 0
rate = 1
clix = 0
def clicking(clix, rate):
while True:
time.sleep(1)
clix += rate
q.put(clix)
threading.Thread(target=clicking, args=(clix, rate)).start()
curr = q.get()
print(curr)
print('\nClicker Starting...')
endgame = False
while not endgame:
print(f'Clix: {curr}')
print('1. Apple : 10 clix | 2. Orange : 8 clix | 3. Exit')
ch = int(input('\nPurchase ID: '))
if ch == 1 and curr >= 10:
print(f'You have {curr} clix.')
print('Got an Apple!')
apple += 1
rate += 1.1
curr -= 10
elif ch == 2 and curr >= 8:
print('Got an Orange!')
orange += 1
rate += 1.2
curr -= 8
elif ch == 3:
endgame = True
stopflag = True
else:
print('Need more Clix')
But my otuput is always 1 instead of incrementing every second by defined rate. What am I missing? I even tried return clix in place of q.put(clix) but didn't work.
the problem is that you are not updating the curr variable inside the while loop. But do notice that when you write "curr = q.get()" inside the while loop it will get the next value in the queue and not the last value (as I suppose you intend). I guess a more straightforward approach is to keep track on the seconds increment inside your while loop using time.time()
import time
apple = 0
orange = 0
rate = 1
clix = 0
curr = 0
last_ts = time.time()
print('\nClicker Starting...')
endgame = False
while not endgame:
ts = time.time()
curr += (ts - last_ts) * rate
last_ts = ts
print(f'Clix: {curr:.0f}')
print('1. Apple : 10 clix | 2. Orange : 8 clix | 3. Exit')
ch = int(input('\nPurchase ID: '))
if ch == 1 and curr >= 10:
print(f'You have {curr:.0f} clix.')
print('Got an Apple!')
apple += 1
rate *= 1.1 # I guess you meant x1.1
curr -= 10
elif ch == 2 and curr >= 8:
print('Got an Orange!')
orange += 1
rate *= 1.2 # I guess you meant x1.2
curr -= 8
elif ch == 3:
endgame = True
stopflag = True
else:
print('Need more Clix')
this way you can exit properly also, notice that on your example even when the loop breaks the thread continues.
but in case you want to maintain a background thread, I suggest creating a class and storing class variables for the current counter and run condition.

Error: List indices are supposed to be an integer but it is an integer

I'm trying to create a while loop and have the index increase by 1 every time the loop runs.
I have n set to zero, which should tell python that this is an integer. However, when it gets to if contact_list[n]['vid'] == '':, it sees n as a string.
Here is the loop. Any help is greatly appreciated:
has_more = True
n = 0
while has_more:
parameters = urllib.parse.urlencode(parameter_dict)
get_url = get_all_contacts_url + parameters + property_params
r = requests.get(url= get_url, headers = headers)
response_dict = json.loads(r.text)
has_more = response_dict['has-more']
contact_list.append(response_dict['contacts'])
parameter_dict['vidOffset']= response_dict['vid-offset']
if len(contact_list) >= max_results:
max_results += 100
if contact_list[n]['vid'] == '':
break
contact_count += 1
print('loop finished')
list_length = len(contact_list)
print("List Length:",list_length)
print("You've succesfully parsed through {} contact records and added them to a list".format(list_length))
Try this:
if 'vid' in contact_list:
if contact_list[n] == '':
break
Hope that helps!
Yes, and realized n is actually not being incremented, if that's the case just call 0 as the list index without having to assign n=0.

How can I check for a key press at any point during a loop?

I am trying to make a timer that counts down to 0, then starts counting up. I am using the time and keyboard modules.
The keyboard module from PyPi.
Everything works as expected, and I am able to press a button to close the program, but it only works at the beginning of each iteration. Is there a way for it to check for a key press at any point while the loop is running? Do I need to be using a different module?
This is my code:
import time
import keyboard
m = 2
s = 0
count_down = True
while True:
if keyboard.is_pressed('q'):
break
print(f"{m} minutes, {s} seconds")
if count_down:
if s == 0:
m -= 1
s = 60
s -= 1
elif not count_down:
s += 1
if s == 60:
m += 1
s = 0
if m == 0 and s == 0:
count_down = False
time.sleep(1)
Using callback is common approach in such case, here is solution:
import time
import keyboard
m = 2
s = 0
count_down = True
break_loop_flag = False
def handle_q_button():
print('q pressed')
global break_loop_flag
break_loop_flag = True
keyboard.add_hotkey('q', handle_q_button)
while True:
if break_loop_flag:
break
print(f"{m} minutes, {s} seconds")
if count_down:
if s == 0:
m -= 1q
s = 60
s -= 1
elif not count_down:
s += 1
if s == 60:
m += 1
s = 0
if m == 0 and s == 0:
count_down = False
time.sleep(1)
If you want to do any two things in parallel, independently of another, you need to consider using multiprocessing. However, even if you do, your loop will either still need to check if a key has been registered in the other process, or you need to terminate the process running the loop forcefully, which may result in unexpected outcomes.
However, in your case, since there are no side effects like files being written, this would work:
import time
import keyboard
from multiprocessing import Process
def print_loop():
m = 2
s = 0
count_down = True
while True:
print(f"{m} minutes, {s} seconds")
if count_down:
if s == 0:
m -= 1
s = 60
s -= 1
elif not count_down:
s += 1
if s == 60:
m += 1
s = 0
if m == 0 and s == 0:
count_down = False
time.sleep(1)
def main():
p = Process(target=print_loop)
p.start()
# this loop runs truly in parallel with the print loop, constantly checking
while True:
if keyboard.is_pressed('q'):
break
# force the print loop to stop immediately, without finishing the current iteration
p.kill()
if __name__ == '__main__':
main()

Undefined dictionaries in my main function

def monday_availability(openhours_M): #openhours_M = number hours pool is open
hourone = int(input('Input the first hour in the range of hours the guard can work'))
hourlast = int(input('Input the last hour in the range of hours the guard'))
hour = 1
availability_M = []
while hour <= openhours_M:
if hour >= hourone & hour <= hourlast:
availability_M.append(1)
else:
availability_M.append(0)
return availability_M
Above is a function gathering the availability of a lifeguard and storing the hours a guard can work as a 1 in availability list or a 0 if they cannot. I return this list with the intent of adding it to a dictionary in the function below.
def guard_availability(guards, openhours_M, openhours_T, openhours_W,
openhours_R, openhours_F, openhours_S, openhours_Su):
continueon = 1
while continueon == 1:
name = input('Input guards name of lifeguard to update availability' )
availability = {}
days = {}
if openhours_M != 0:
monday_availability(openhours_M)
if openhours_T != 0:
tuesday_availability(openhours_T)
if openhours_W != 0:
wednesday_availability(openhours_W)
if openhours_R != 0:
thursday_availability(openhours_R)
if openhours_F != 0:
friday_availability(openhours_F)
if openhours_S != 0:
saturday_availability(openhours_S)
if openhours_Su != 0:
sunday_availability(openhours_Su)
days['Monday'] = availability_M
days['Tuesday'] = availability_T
days['Wednesday'] = availability_W
days['Thursday'] = availability_R
days['Friday'] = availability_F
days['Saturday'] = availability_S
days['Sunday'] = availability_Su
availability[name]= days
continueon = input('Enter 1 to add availability for another guard, 0 to stop: ')
return days
When I run this code, I get an error saying my availability lists are undefined even though I returned them in the functions above. Where is the error in my understanding of returning in functions, and how can I remedy this problem.
monday_availability(openhours_M) returns a value.
Returning a variable does not assign it to anything outside the scope of that function.
If you renamed return availability_M to use return foo and update the other uses only within that function accordingly, would the error make more sense?
Now, actually capture the result
availability_M = monday_availability(openhours_M)
Or even just
days['Monday'] = monday_availability(openhours_M)
Also, not seeing how that function has anything to do with Mondays. Try to write DRY code
You return the dic value in your function but don't assign it to any variable. You should do it like this:
if openhours_M != 0:
availability_M=monday_availability(openhours_M)
if openhours_T != 0:
availability_T=tuesday_availability(openhours_T)
if openhours_W != 0:
availability_W=wednesday_availability(openhours_W)
if openhours_R != 0:
availability_R=thursday_availability(openhours_R)
if openhours_F != 0:
availability_F=friday_availability(openhours_F)
if openhours_S != 0:
availability_S=saturday_availability(openhours_S)
if openhours_Su != 0:
availability_Su=sunday_availability(openhours_Su)

How to keep a function going after different function has been called?

I believe my program is freezing after:
if pressed(win.getMouse(), startImage):
task = 'start'
timeFormat()
Basically, what I'm trying to do is when the mouse point is on stopImage the timer will stop, and when the mouse click is on lapTimer, it will reset. When I take out
timeFormat()
the program will run through the while and then break. My stop and start button work, but not my lap button. How can i make it NOT stop the program after the stop button is pressed? So that I can hit start again or reset?
def pressed(pt, image):
width = image.getWidth()
height = image.getHeight()
anchor = image.getAnchor()
x1 = (anchor.getX()) - (.5 * width)
x2 = (anchor.getX()) + (.5 * width)
y1 = (anchor.getY()) - (.5 * height)
y2 = (anchor.getY()) + (.5 * height)
return(x1 <= pt.getX() <= x2 and y1 <= pt.getY() <= y2)
def timeFormat():
sec = 0
minute = 0
hour = 0
timeDisplay = "{0:02d}:{1:02d}:{2:02d}".format(hour, minute, sec)
timer.setText(timeDisplay)
while task == 'start':
task = 'start'
time.sleep(1)
sec += 1
if sec == 60:
sec = 0
minute += 1
if minute == 60:
sec = 0
minute = 0
hour += 1
timeDisplay = "{0:02d}:{1:02d}:{2:02d}".format(hour, minute, sec)
timer.setText(timeDisplay)
check = win.checkMouse()
if check != None:
if pressed(check, stopImage):
task = 'stop'
print('asd')
if pressed(check, startImage):
task = 'start'
if pressed(check, lapImage):
sec = 0
minute = 0
hour = 0
task = 'stop
def main():
while not pressed(win.getMouse(), startImage):
if task == 'stop':
break
if task == 'reset':
sec = 0
minute = 0
hour = 0
break
continue
timeFormat()
main()
Your timeFormat function never returns, so the calling code can't continue.
Your main loop has the condition while sec < 60, but every time sec is incremented to 60, it gets reset to zero again. This means the loop will never end.
It's not clear to me when you expect it to end, so I can't necessarily tell you how to fix the issue, but generally it's a bad idea when writing an interactive program to have multiple event loops unless you have a well defined structure for switching between them.
You have a lot of loops, and when one of them is running, all the others will necessarily be stuck waiting. Try moving some of the logic from separate loops into other functions that can be called from a single main loop.
All I had to do was switch some if statements around.

Categories