You can try wrapping that code in a try/except block, because keyboard interrupts are just exceptions:
try:
while True:
IDs2=UpdatePoints(value,IDs2)
time.sleep(10)
except KeyboardInterrupt:
print('interrupted!')
Then you can exit the loop with CTRL-C.
Answer from Jess on Stack OverflowYou can try wrapping that code in a try/except block, because keyboard interrupts are just exceptions:
try:
while True:
IDs2=UpdatePoints(value,IDs2)
time.sleep(10)
except KeyboardInterrupt:
print('interrupted!')
Then you can exit the loop with CTRL-C.
You could use exceptions. But you only should use exceptions for stuff that isn't supposed to happen. So not for this.
That is why I recommand signals:
import sys, signal
def signal_handler(signal, frame):
print("\nprogram exiting gracefully")
sys.exit(0)
signal.signal(signal.SIGINT, signal_handler)
you should put this on the beginning of your program and when you press ctrl+c wherever in your program it will shut down gracefully
Code explanation:
You import sys and signals.
Then you make a function that executes on exit. sys.exit(0) stops the programming with exit code 0 (the code that says, everything went good).
When the program get the SIGINT either by ctrl-c or by a kill command in the terminal you program will shutdown gracefully.
A way to clean up the use of CTRL-C is to use try-except to catch the KeyboardInterrupt like:
try:
while True:
...
...
except KeyboardInterrupt:
exit
The last three lines I added will allow you to break out of the loop with any key being pressed. Dont forget the import of msvcrt
import time, win32api
import msvcrt
cursorX = 0
cursorY = 0
while True:
cursorX, cursorY = win32api.GetCursorPos()
time.sleep(600)
cursorX = cursorX + 10
win32api.SetCursorPos((cursorX,cursorY))
cursorX, cursorY = win32api.GetCursorPos()
time.sleep(600)
cursorX = cursorX - 10
win32api.SetCursorPos((cursorX,cursorY))
if msvcrt.kbhit():
if ord(msvcrt.getch()) != None:
break
The easiest way is to just interrupt it with the usual Ctrl-C (SIGINT).
try:
while True:
do_something()
except KeyboardInterrupt:
pass
Since Ctrl-C causes KeyboardInterrupt to be raised, just catch it outside the loop and ignore it.
There is a solution that requires no non-standard modules and is 100% transportable:
import _thread
def input_thread(a_list):
raw_input() # use input() in Python3
a_list.append(True)
def do_stuff():
a_list = []
_thread.start_new_thread(input_thread, (a_list,))
while not a_list:
stuff()
As long as you're okay with restarting "from the top" after each interrupt (as opposed to returning to the exact point in the loop when the signal was raised, which is a much harder problem):
while True:
try:
controller.main_loop()
except KeyboardInterrupt:
controller.set_coefficients()
In case you don't want a separate thread for IO, generators may be used to preserve the state of your loop across KeyboardInterrupts.
some_parameter = 1
def do_pid_stuff():
while True:
sensor_data1 = 'data'
sensor_data2 = 'data'
sensor_data3 = 'data'
yield 'based on sensor_data1 ' * some_parameter
yield 'based on sensor_data2 ' * some_parameter
yield 'based on sensor_data3 ' * some_parameter
stuff = do_pid_stuff()
while True:
try:
for control_signal in stuff:
print(control_signal)
except KeyboardInterrupt:
some_parameter = int(input())
So the main loop will continue with new parameters from the last executed yield. This however would require to rewrite your loop. Probably, it should be splitted into a generator that will give you sensor data and into a function that will actually do stuff based on the sensor values.
just indent your code correctly:
def determine_period(universe_array):
period=0
tmp=universe_array
while True:
tmp=apply_rules(tmp)#aplly_rules is a another function
period+=1
if numpy.array_equal(tmp,universe_array) is True:
return period
if period>12: #i wrote this line to stop it..but seems its doesnt work....help..
return 0
else:
return period
You need to understand that the break statement in your example will exit the infinite loop you've created with while True. So when the break condition is True, the program will quit the infinite loop and continue to the next indented block. Since there is no following block in your code, the function ends and don't return anything. So I've fixed your code by replacing the break statement by a return statement.
Following your idea to use an infinite loop, this is the best way to write it:
def determine_period(universe_array):
period=0
tmp=universe_array
while True:
tmp=apply_rules(tmp)#aplly_rules is a another function
period+=1
if numpy.array_equal(tmp,universe_array) is True:
break
if period>12: #i wrote this line to stop it..but seems its doesnt work....help..
period = 0
break
return period
def determine_period(universe_array):
period=0
tmp=universe_array
while period<12:
tmp=apply_rules(tmp)#aplly_rules is a another function
if numpy.array_equal(tmp,universe_array) is True:
break
period+=1
return period
How can I make this work because it's really annoying to keep quitting cmd and then re-navigating to my files. Thanks
Don't use bare except (except statement without an exception type specified): in Python, Ctrl-C is converted to an exception and raised. This means except without any more information will catch it, and execute whatever exception handling code you defined.
In Python, you almost always want to explicitly catch Exception as it includes most exceptions but importantly excludes KeyboardInterrupt (which is what Ctrl-C translates to) and SystemExit (which is what sys.exit() triggers). See the exceptions hierarchy.
The main exception to this is performing cleanup then re-raising directly, in that case a bare except is acceptable (though often unnecessary because if the process is killed you usually don't need to close files or the like).
Incidentally the same applies if you ever need to define your own exception: it should extend Exception unless it's a system-type exception which generally should not be caught and resumed from.
Try and Except blocks are used for catching scenarios that are unprecedented or not accounted for a developer, Say
- You are accessing a file and somehow the file was deleted.
- You are accessing a database and connection was lost.
- You lost contact of something and you cannot predict how it will affect it.
The reason you are not being able to exit the program is because it catched an error and moving to except block which is how to handle it.
More Information : https://www.w3schools.com/python/python_try_except.asp
So basically what I did in the code below is that we are telling it to exit incase you are giving a signal of keyboard interrupt (Ctrl + c ) to stop the program which is as below.
The concept is called signal handling and is used in prod environments.
You can my github link below for the source code : https://github.com/SugaanthMohan/Python_Tools/blob/master/SignalHandling/SignalHandling.py
If you want your code to stop only by keyboard Interrupt Ctrl+C, Use the code below.
def run():
print('\t==================== Welcome to the Black Jack Casino ====================\n')
while True:
try:
player_chips = int(input('How many chips do you want to buy? '))
break
except:
print('Don\'t muck me about... ')
except KeyboardInterrupt:
raise SystemExit
cash_out = False
dealer = Dealer()
player = Player()
player.chips = player_chips
while not cash_out or player.chips >= 0:
try:
player_bet = int(input('Place a bet: '))
if player_bet > player.chips:
print('You don\'t have the readies mate...')
else:
start_game(dealer, player, player_bet)
try:
quit = input('You want to continue? (Y/N) ')
if quit.lower() == 'n':
cash_out = True
except:
print('Don\'t talk rubbish...')
except KeyboardInterrupt:
raise SystemExit
except:
print('Don\'t waste my time...')
continue
except KeyboardInterrupt:
raise SystemExit
try:
play_again = input('Fancy another game? (Y/N)')
if play_again.lower() == 'y':
run()
else:
print('Next time then sucker...')
return
except:
print('Don\'t talk rubbish...')
except KeyboardInterrupt:
raise SystemExit
You need to use threading.
import threading
x = True
def thread_function():
while x is True:
pass #printing timer to CLI here
threading.Thread(target=thread_function).start()
# Continue with the other steps you want to take
# ...
# This will terminate the timer loop
x = False
Python threading documentation: https://docs.python.org/3/library/threading.html
If you want to print the time always at the same line you need to control terminal cursor. For more information checkout: How can move terminal cursor in Python?
Thanks to @dorukerenaktas, I have got this working. This is their answer adapted into my scriptlet:
import threading
from os import system
timer_thread = None
def timer(stawt, stahp, step, time_step):
from time import sleep
global run_timer
stawt = int(stawt)
stahp = int(stahp)
if stahp < 1:
print('Sorry, I limit min count to 1 second!\n')
stahp = 1
elif stahp > 1000:
print('Sorry, I limit max count to 1000 seconds!\n')
stahp = 1000
else:
print()
stahp = stahp * 100 + 1
titerator = iter(range(stawt, stahp, step))
def print_time():
while run_timer is True:
try:
current_step = str(next(titerator))
if int(current_step) < 99:
final_time = '0' + current_step[:0] + '.' + current_step[0:] + 's'
print('\r' + final_time, end='')
elif int(current_step) < 999:
final_time = current_step[:1] + '.' + current_step[1:] + 's'
print('\r' + final_time, end='')
elif int(current_step) < 9999:
final_time = current_step[:2] + '.' + current_step[2:] + 's'
print('\r' + final_time, end='')
else:
final_time = current_step[:3] + '.' + current_step[3:] + 's'
print('\r' + final_time, end='')
sleep(time_step)
except:
break
seconds = int((int(current_step) / 100) % 60)
minutes = int((int(current_step) / 100) // 60)
if minutes < 1:
return ''
else:
final_time_human = str(minutes) + 'm ' + str(round(seconds)) + 's'
print('\n' + final_time_human)
print_time()
def _init_timer():
global run_timer; run_timer = True
global timer_thread
print('Enter max number of seconds to count: ', end='')
count_to = float(input())
timer_thread = threading.Thread(target=timer, args=(0, count_to, 1, 0.01))
timer_thread.start()
print('\rPress enter to stop the timer:')
usr_input = input(); run_timer = False
system('clear')
_init_timer()
timer_thread.join()
print('\nGoodbye!')
- Raise an exception, that you can handle outside the While loop
- Return a flag to be captured by the caller and handle accordingly. Note,
"if logic" directly in the while loop,, would be the most preferred way.
Python has a cool feature in generators - these allow you to easily produce iterables for use with a for loop, that can simplify this kind of code.
def input_until(message, func):
"""Take raw input from the user (asking with the given message), until
when func is applied it returns True."""
while True:
value = raw_input(message)
if func(value):
return
else:
yield value
for value in input_until("enter input: ", lambda x: x == "exit"):
...
The for loop will loop until the iterator stops, and the iterator we made stops when the user inputs "exit". Note that I have generalised this a little, for simplicity, you could hard code the check against "exit" into the generator, but if you need similar behaviour in a few places, it might be worth keeping it general.
Note that this also means you can use it within a list comprehension, making it easy to build a list of results too.
Edit: Alternatively, we could build this up with itertools:
def call_repeatedly(func, *args, **kwargs):
while True:
yield func(*args, **kwargs)
for value in itertools.takewhile(lambda x: x != "exit",
call_repeatedly(raw_input, "enter input: ")):
...
Multiprocessing rather than Threading was a much nicer solution. Instead of:
x = threading.Thread(target = function1, daemon=True)
I use:
x = multiprocessing.Process(target = function1, daemon=True)
My Stop function then just becomes:
def stop_all()
Stop motor
x.terminate()
x.join()
I just had to start and then immediately stop function1 so that the multiprocess "x" was defined before I tried to define stop_all()
One way to do this is to use a threading.Lock, and to use threading.Lock.acquire with a timeout as a replacement for time.sleep.
When you try to acquire the lock with a timeout when the lock has already been acquired, it waits for the timeout to expire before returning False. This behaviour is similar to time.sleep, however if the lock is released during this "sleeping" time, then it returns True immediately. Similarly, if the lock has already been released when threading.Lock.acquire is called, then it returns True immediately.
The ThreadStopper class implemented below provides a neater interface for managing this use case for a lock.
The below example demonstrates how to use the ThreadStopper class. The code starts 4 threads, which print something every 5 seconds, and when you press the Enter key a random one is stopped immediately, even if currently "sleeping".
Note that each thread needs it's own ThreadStopper passed to it.
import threading
import time
import random
class ThreadStopper:
def __init__(self):
self.lock = threading.Lock()
self.lock.acquire()
self.alive = True
def sleep(self, t):
if self.lock.acquire(timeout=t):
self.alive = False
def stop(self):
self.lock.release()
self.alive = False
num_threads = 4
thread_stoppers = []
threads = []
def worker(ts, i):
print(f'I am thread {i}')
while ts.alive:
print(f'Thread {i} looping')
ts.sleep(5) # ThreadStopper.sleep, not time.sleep
print(f'Thread {i} finished')
for i in range(num_threads):
thread_stopper = ThreadStopper()
# create the thread, passing the newly created ThreadStopper
thread = threading.Thread(target=worker, args=(thread_stopper, i))
thread.start()
thread_stoppers.append(thread_stopper)
threads.append(thread)
time.sleep(0.5)
running = set(range(num_threads))
while running:
input() # wait for enter to be pressed
thread_to_stop = random.choice(list(running))
thread_stoppers[thread_to_stop].stop() # signal the ThreadStopper to stop
running.remove(thread_to_stop)
for thread in threads:
thread.join()