I'm making a Discord bot with a lot of commands that take a while to finish (like loops) so I'd like to also have a command that stops any actively running code. I've tried sys.exit but I don't want to have to restart the program each time before it will take another input. Anyone know what I can do?
It will depend on the way your code is formatted, but you will probably want to use functions that utilize boolean or return statements:
def foo():
if end_this:
return
# stuff
If you have some tracking boolean end_this that is set to True, the function foo() will not execute everything below. Alternatively, you could use a while-loop with a break in your code:
def foo():
while True: # runs forever unless ended
# stuff
break
Now, foo() will continue indefinitely until the break statement is reached. An if-statement can enclose the break, setting some logic on when the break occurs. Again, this may require a main() function to handle the calls and ends of your previous functions, but it would allow following code/functions to execute.
Is it possible to return from a function and continue executing code from just under the function. I know that may sound vague but here is an example:
def sayhi():
print("hi")
continue_function() #makes this function continue below in stead of return
#the code continues here with execution and will print hey
print("hey")
sayhi()
when executing this the code should do this:
it prints "hey"
it calls the sayhi() function
it prints "hi"
it calls a function to make it continue after the function (in theory similar behavour could be achieve by using decorators)
it prints "hey" again
it calls sayhi() again
etc
i am fully aware of the fact that similar behaviour can be achieved by just using for loops but for the project i am working on this functionality is required and not achievable by using looping.
some solutions i have thought of (but i have no clue how i could execute them) are:
somehow clearing the stack python uses to return from one function to another
changing return values
changing python itself (just to make clear: it would solve the problem but it is something i do not want to do beacuse the project must be usable on non-altered versions of python
using some c extension to change python's behaviour from within python itself
Repetition without loops can be done with recursion:
def sayhi():
print("hey")
print("hi")
sayhi()
sayhi()
I assume you have some terminating condition to insert. If not, this code will give a RecursionError.
class MyClass():
def __init__(self):
...
def start(self):
colorThread = threading.Thread(target = self.colorIndicator())
colorThread.start()
while True:
print ('something')
...
...
I also have a print statement inside the colorIndicator(). That statement is getting printed. But the print statement inside the while loop of start() method isn't displayed on screen.
The colorIndicator() also has an infinite loop. It gets some data from the internet and updates a counter. This counter is initialized inside __init__ as self variable and I'm using that variable inside other methods.
I do not understand why print inside while is not being executed.
colorIndicator function:
def colorIndicator(self):
print ('something else')
...
while (True):
...
print ('here')
time.sleep(25)
The output I get is the following:
something else
here
here
I stopped it after that. So, the colorIndicator is clearly running completely.
I'm calling the script with import in a python interpreter (in a terminal). Then I instantiate MyClass and call the start function.
You're not actually running colorIndicator in a thread, because you called it in the main thread, rather than passing the method itself (uncalled) as the thread target. Change:
colorThread = threading.Thread(target=self.colorIndicator())
# ^^ Agh! Call parens!
to:
# Remove parens so you pass the method, without calling it
colorThread = threading.Thread(target=self.colorIndicator)
# ^ Note: No call parens
Basically, your problem is that before you ever construct the Thread, it's trying to run colorIndicator to completion so it can use its return value as the target, which is wrong in multiple ways (the method never returns, and even if it did, it wouldn't return a callable suitable for use as a target).
So I have a small python program that is spread out across a few classes. In my main class, I tell my title screen class to display and then wait for input. If the input it gets is 'q' it calls back to my main class telling it to set it's stop flag to true. Otherwise, it just loops.
This is the callback I give to my title screen:
def quit():
stopped = True
stopped is set to False outside of the callback. The callback is registered fine, and goes off no problem, but it seems to set stopped to true locally in titlescreen, and not in main. I can fix this by creating a class stopFlag and doing the exact same thing, except in the object.
My question is why do I need to make a new class to do this? Is there a way I can set a global flag in main which is just a boolean without making an object out of it? How can I have the callback reference that boolean?
Edit:
I declare stopped like this:
stopped = False
Here is the quit callback register call:
titleScreen.registerCallbackQuit(quit)
Which looks like:
def registerCallbackQuit(self, callback):
self.callbackQuit = callback
And it calls quit if it gets a in the user input.
global stopped would work (probably). People use classes to avoid globals (among other things). If 'stopped' is spread out over many files, you would need to import it.
I have a problem in managing a infinite while loop in Python, in which I would insert a timer as a sort of "watchdog". I try to explain better: the script has to listen on a serial channel and wait for messages coming from sensors connected on the other side of the channel.
I do this with a while True loop because the script must catch all the signals that are passing. However, even if it's probably unnecessary, i would like to insert a timer which is always reset every loop. So, if (for example) the loop get stuck for some reason, the timer will end and will exit the program. I thought i could do this in this way:
def periodicUpdate():
exitTimer = threading.Timer(60.0, sys.exit())
while True:
exitTimer.start()
readData()
exitTimer.cancel()
Now, the problem is that when i start the script it immediatly exit. It seems that it reads sys.exit() before all the rest, and it doesn't respect the construct of the timer, but simply when periodicUpdate is called it exits. Why this happen?! I tried changing the syntax, putting sys.exit in an other function and call that function, i tried other solutions but always it behave in two ways: it exits or it behave as the timer doesn't exists. Can someone help me? Thanks very much
Remove the parentheses. If you use sys.exit(), it will fire straight away. When you use sys.exit, it will pass the function as Timer's second argument.
I think your approach is not the best one, instead of running a timer that exits the application, why not simply timeout the function that reads the data:
Timeout on a function call
It seems that it reads sys.exit() before all the rest
Sure it does. The second argument of threadint.Timer is a function that will be called. What you do is you actually call sys.exit and supply its return value (which is undefined, by the way, since the call terminates the program) as a function to be called. That's an error, since sys.exit's return value is not a function, but that doesn't matter, as the program is terminated anyway.
What you want to do is
exitTimer = threading.Timer(60.0, sys.exit) # note: no brackets
But that actually will not work, as sys.exit in the thread will terminate only that thread. In short, you can't use a watchdog to terminate a stuck while-loop if this loops is in your main thread. In your particular situation you should investigate the function you are using to read data, most likely it lets you set a read timeout.
It seems to me that none of the solutions proposed here actually works. This is an example of code. Would be great to know how to fix it. Also, please try it before answering.
import time, threading, sys
def _exit():
print 'exiting'
sys.exit()
def periodicUpdate():
exitTimer = threading.Timer(2.0, _exit)
while True:
exitTimer.start()
print 'go'
time.sleep(5)
exitTimer.cancel()
periodicUpdate()
The actual output is:
$python test.py
go
exiting
RuntimeError: threads can only be started once
exitTimer = threading.Timer(60.0, sys.exit)
Remove the () from sys.exit in timer call
def _exit()
sys.exit()
def periodicUpdate():
exitTimer = threading.Timer(60.0, _exit)
while True:
exitTimer.start()
readData()
exitTimer.cancel()
In you put the () the interpreter call this function if not the interpreter get a reference for this function.
Have fun :)
Edit: Use of _exit
threading.Timer(60.0, os._exit, [0])
def periodicUpdate():
exitTimer = sys.exit(60.0, sys.exit())
while sys.exit():
sys.exit()
readData()
sys.exit()
if __name__ == "__main__":
sys.exit()
Don't forget to import sys.