Terminate loop at any given time - python

I have the following code which turns an outlet on/off every 3 seconds.
start_time = time.time()
counter = 0
agent = snmpy4.Agent("192.168.9.50")
while True:
if (counter % 2 == 0):
agent.set("1.3.6.1.4.1.13742.6.4.1.2.1.2.1.1",1)
else:
agent.set("1.3.6.1.4.1.13742.6.4.1.2.1.2.1.1", 0)
time.sleep(3- ((time.time()-start_time) % 3))
counter = counter + 1
Is there a way I can have the loop terminate at any given point if something is entered, (space) for example... while letting the code above run in the mean time

You can put the loop in a thread and use the main thread to wait on the keyboard. If its okay for "something to be entered" can be a line with line feed (e.g., type a command and enter), then this will do
import time
import threading
import sys
def agent_setter(event):
start_time = time.time()
counter = 0
#agent = snmpy4.Agent("192.168.9.50")
while True:
if (counter % 2 == 0):
print('agent.set("1.3.6.1.4.1.13742.6.4.1.2.1.2.1.1",1)')
else:
print('agent.set("1.3.6.1.4.1.13742.6.4.1.2.1.2.1.1", 0)')
if event.wait(3- ((time.time()-start_time) % 3)):
print('got keyboard')
event.clear()
counter = counter + 1
agent_event = threading.Event()
agent_thread = threading.Thread(target=agent_setter, args=(agent_event,))
agent_thread.start()
for line in sys.stdin:
agent_event.set()

Related

Which is Faster Counter Python

I wanted to know which one faster counter
1)
from threading import Thread
def c(output, i):
if i in output:
output[i] += 1
else:
output[i] = 1
def build(itera):
output = {}
for i in itera:
Thread(target=c, args=(output, i)).start()
return output
def build(itera):
output = {}
for i in itera:
if i in output:
output[i] += 1
else:
output[i] = 1
return output
from collections import Counter
Counter("12342")
And if any code which performs same this but is faster all all three block of code please tell me
Use this to figure out which methods takes the least amount of time:
import time
start = time.time()
***
The code you want to test out
***
end = time.time()
time_taken = round(end - start), 2
print(time_taken)
The output is in seconds.
Using timeit:
import timeit
def do_something():
pass
timeit.timeit(f"{do_something()}")
Add this into your code, and see which runs quicker:
from datetime import datetime
start = datetime.now()
#code here
end = datetime.now()
total = end - start
print(total.total_seconds())

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()

How can I optimize my multiprocessing in python?

I am trying to run multiProcessing in python for the first time but when I debug in PyCharm I see that Thread 8 is waiting for a lock and I believe this is where my code is slowing down. I thought about mapping process pool in the while loop but this seems redundant to do this. Am i on the right track with this?
import random
import time
import math
import multiprocessing as mp # alias
# from multiprocessing.dummy import Pool as ThreadPool
# initial sequence:
# HHTHTHHHTHHHTHTH
coinChoices = ["H", "T"] # choices
idealFlip = "HHTHTHHH" # string to match
flip = "" # resets flip
margin_error = 0.1 # accuracy
num_matches = 0.0 # matched strings
probability = 0 # calc. probability
counter = 0 # iterations
flag = 1 # exit token
secondFlag = 1
check = math.ceil(pow(2, len(idealFlip))/2) # used for printing prob
# flips a coin *NOT USED*
def flip_coin(coins):
return str(random.choice(coins))
# requests (num) tasks to be completed
def flip_coin_num(num):
return str(random.choice(coinChoices))
# theoretical probability
def compute_probability():
size = len(idealFlip)
return math.pow(0.5, size)
# actual probability
def empirical_probability(count, num_flips):
return count / num_flips
# TODO: implement multiprocessing
if __name__ == "__main__":
# print("# cores: %d" % mp.cpu_count())
probability = compute_probability()
print("\nInitial probability of landing on the sequence: " + str(probability) + "\n")
actualProb = 0
empiricalProb = 0
tasks = range(len(idealFlip))
pool = mp.Pool(processes=4)
while flag != 0 or counter == 1000:
temp = pool.map(flip_coin_num, tasks)
# add other processes?
# handles close / join
flip = "".join(temp)
# print(temp)
# print(flip)
if counter != 0:
empiricalProb = empirical_probability(num_matches, counter)
if flip == idealFlip:
num_matches += 1
counter += 1
flip = ""
if counter % check is 0:
print("Probability" + str(empricalProb))

How can I get loops to run sequentially without locking GUI?

I'm writing a photobooth program in Python on my Raspberry Pi 2 and it worked if I just want to take one picture or use auto focus once. I'm trying to write a function "scheduler" that waits 4 seconds then runs auto-focus, then waits 4 seconds to take picture 1, waits another 4 seconds for picture 2 and waits 4 seconds for picture 3 while updating a status bar in PyGTK. But when the "scheduler" function is called it goes through and starts all the while loops at the same time.
I tried putting the while loops in separate functions and running them as threads and using threadx.start(), threadx.join() commands under each thread call. I suspect the way gobject.timeout_add() function is preventing blocking, which I need to keep the GUI updated and the live preview running, but I also can't figure out how to get blocking when I need it. I also started scheduler as a thread and used time.sleep(1) in each of the while loops and it acts behaves how I want it to except the GUI disappears after the first image gets processed and I can't find any error message to explain it.
I've been working on this for weeks and would happily pay someone to help me get this finished via email. I live in a rural area and have had a very hard time finding someone locally to help. I can paypal... please contact me at derosia at the popular google email service. If you have a camera supported by gphoto2 and a usb tether that would be a bonus.
class Photobooth(gtk.Window):
def set_statusBar(self, status):
self.statusBar.label.set_text(str(status))
def focus_counter2(self, counter):
if counter > 3:
self.set_statusBar("Get into position!")
elif counter > 0:
self.set_statusBar("Focusing: " + str(counter-1))
else:
self.set_statusBar("Focusing: " + str(counter-1))
self.focus_function() #runs the function for auto focus
def countdown_function(self, counter, image_name):
if counter > 1:
self.set_statusBar(str(counter-1))
elif counter > 0:
self.set_statusBar("Keep Smiling!")
else:
self.photo_cb(image_name) #runs the function to take an image
def scheduler(self, widget, data = None):
global ftp_path
global image_names
global countdown_timer
image_names = []
counter = countdown_timer
while counter > 0:
gobject.timeout_add(counter * 1000, self.focus_counter2, countdown_timer-counter)
counter -= 1
counter = countdown_timer
while counter >= 0:
image_name = datetime.datetime.now().strftime("%Y_%m-%d_%H-%M-%S")
gobject.timeout_add(counter * 1000, self.countdown_function, countdown_timer-counter, image_name)
counter -= 1
image_names.append(image_name + ".jpg")
counter = countdown_timer
while counter >= 0:
image_name = datetime.datetime.now().strftime("%Y_%m-%d_%H-%M-%S")
gobject.timeout_add(counter * 1000, self.countdown_function, countdown_timer-counter, image_name)
counter -= 1
image_names.append(image_name + ".jpg")
counter = countdown_timer
while counter >= 0:
image_name = datetime.datetime.now().strftime("%Y_%m-%d_%H-%M-%S")
gobject.timeout_add(counter * 1000, self.countdown_function, countdown_timer-counter, image_name)
counter -= 1
image_names.append(image_name + ".jpg")
def __init__(self):
super(PictureBox, self).__init__()
startB_image = gtk.image_new_from_stock(gtk.STOCK_YES, gtk.ICON_SIZE_SMALL_TOOLBAR)
startB = gtk.Button()
startB.set_image(startB_image)
startB.set_tooltip_text("Start countdown")
startB.connect('clicked', self.scheduler, None)
Thanks to andlabs I solved this the way he suggested:
Call a function and have each function call the next one when they finished what they were doing. Then to make sure it looped through the proper number of times I just passed along a counter to each function that got iterated at the end of each loop, image_number. It seems to work.
class Photobooth(gtk.Window):
def set_statusBar(self, status):
self.statusBar.label.set_text(str(status))
def focus_counter1(self, widget, data=None):
global countdown_timer
counter = countdown_timer
while counter > 0:
gobject.timeout_add(counter * 1000, self.focus_counter2,
countdown_timer-counter)
counter -= 1
def focus_counter2(self, counter):
if counter > 3:
self.set_statusBar("Get into position!")
elif counter > 0:
self.set_statusBar("Focusing: " + str(counter))
else:
self.set_statusBar("Focusing: " + str(counter))
self.focus_function()
gobject.timeout_add(1000, self.countdown_clicked, 1)
def countdown_clicked(self, image_number):
global countdown_timer
counter = countdown_timer
while counter >= 0:
gobject.timeout_add(counter * 1000, self.countdown_function,
countdown_timer-counter, image_number)
counter -= 1
def countdown_function(self, counter, image_number):
global images_per_sequence
if counter > 1:
self.set_statusBar(str(counter-1))
elif counter > 0:
self.set_statusBar("Keep Smiling!")
else:
image_name = datetime.datetime.now()
self.photo_cb(image_name.strftime("%Y_%m-%d_%H-%M-%S"))
if image_number < images_per_sequence:
gobject.timeout_add(1000, self.countdown_clicked,
image_number + 1)
def __init__(self):
super(PictureBox, self).__init__()
startB_image = gtk.image_new_from_stock(gtk.STOCK_YES,
gtk.ICON_SIZE_SMALL_TOOLBAR)
startB = gtk.Button()
startB.set_image(startB_image)
startB.set_tooltip_text("Start countdown")
startB.connect('clicked', self.focus_counter1, None)

How to change speed at which text is printed (python)

What I am trying to accomplish is first text appears after 1 second. then 2, ect. till 10. then when time equals 10, the time decreases, so the text appears after 9 seconds, then 8 etc.
How could I fix this code so that it works properly?
The error:
Traceback (most recent call last):
File "C:/Users/Eric/Dropbox/time.py", line 13, in <module>
time.sleep(time)
AttributeError: 'int' object has no attribute 'sleep'
The code :
import time
x = 1
t = 1
time = t + 1
while x == 1:
print time
if time >=10:
time = t - 1
elif time <= 0:
time = t + 1
time.sleep(time)
Edit:
import time
x = 1
t = 1
time1 = 0
while x == 1:
if time1 == 10:
time1 = time1 - 1
elif time1 == 0:
time1 = time1 + 1
else :
time1 = time1 + 1
print time1
time.sleep(time1)
So I changed the program around abit, so I almost works correctly. What it does is count to 10, then 9 then back to 10.
ex. 1,2,3,4,5,6,7,8,9,10,9,10,9,10
how can I set it so that the program increases time to ten then decreases to zero then increases again?
You're overriding the imported time module (line 1) by your own time variable (line 4). You can:
rename your time variable to something else
import time
x = 1
t = 1
time_passed = t + 1 # use "time_passed" instead of "time" for example
while x == 1:
print time_passed
if time_passed >= 10:
time_passed = t - 1
elif time_passed <= 0:
time_passed = t + 1
time.sleep(time_passed)
alias the imported time module with import time as tm the use tm.sleep(time)
import time as tm # alias the time module as "tm" for example
x = 1
t = 1
time = t + 1
while x == 1:
print time
if time >= 10:
time = t - 1
elif time <= 0:
time = t + 1
tm.sleep(time) # use "tm" to refer to the module
only import sleep from time with from time import sleep and use sleep(time) instead
from time import sleep # only import "sleep" from time, not the whole module
x = 1
t = 1
time = t + 1
while x == 1:
print time
if time >= 10:
time = t - 1
elif time <= 0:
time = t + 1
sleep(time) # use "sleep" directly
After fixing this, you also need to somehow remember that you need to either increase or decrease the time at the next iteration. For example:
from time import sleep
x = 1
t = 1
time = t + 1
incr = True
while x == 1:
print time
if time >= 10:
time = 9
incr = False
elif time <= 0:
time = t + 1
incr = True
else:
if incr:
time = time + 1
else:
time = time - 1
sleep(time)
You're redefining 'time' after you import it...
Try using a different variable name.
Your time variable is conflicting with the module (time) that you imported. You could use curTime or myTime instead as your variable name.

Categories