I would like to exit a function by pressing a button using the return statement in the if statement. To write these lines again and again and again is not really what I like. That's why I am basically looking for a function that tells the parent function to return.
Obviously I can't use the return statement in a function and just execute the function where I want to check the variable, although that would be the nicest way I could imagine.
I want to explain it in a loop, but please keep in mind that's not where I want to use it. The usage is for automated processes which should have many exit points.
import keyboard, time
RedFlag = False
def set_RedFlag():
global RedFlag
RedFlag = True
keyboard.add_hotkey("end", set_RedFlag)
PauseFlag = False
def set_PauseFlag():
global PauseFlag
print(PauseFlag)
if PauseFlag == False:
PauseFlag = True
else:
PauseFlag = False
keyboard.add_hotkey("space", set_PauseFlag)
def task():
for i in range(30):
print("test",i)
time.sleep(1)
# Flags
if RedFlag == True: # exitpoint
return
while PauseFlag == True: # pause the script
time.sleep(1/6)
task()
Really relevant is the if statement after #Flags. Especially with the while statement I would have to repeat multiple lines. I would love to have this in one single word as if it was a function.
Edit:
More about the "what for?":
I would like to run a macro and later maybe other tasks. For example writing the odd numbers from 1 to 511. And I want to be able to stop or pause it at any given time.
I forgot to mention, that I tried using the multiprocessing module, since I could terminate the task there. Sadly it is not an option for me not only because the starting time of a process is a bit too long for me, also I am learning a bit about kivy and I know it get's complicated when I want to start another process while using kivy.
Related
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.
I currently have a program that I am working on that requires the user to input some parameters, and then press a button to start the main part of the program.
After the start button is pressed, the if loop executes a sequential order of commands (around 20) and then stops.
I want to be able to stop this sequence of commands at any time during the code using a separate 'stop' button, but I am not sure how. I am more interested in a method of doing this than GUI syntax.
Any help is appreciated.
Example code:
if (start_button_is_pressed):
#do thing a
#do thing b
#do thing c
...
#do thing z
# i want to be able to stop from any point a-z
You can use a loop and break execution at any point. If you want only a single pass through the steps, add a final break at the end.
jump_out = False
while not jump_out:
step_1()
if (jump_out):
break
step_2()
if (jump_out):
break
# and so on
step_n()
break # add unconditional break for single-pass execution
you can use a break statement inside the loop. Set an event such that when the stop button is pressed, it triggers a certain value and this value alters the loop. Sample process below
stop = False
if stop_button_is_pressed:
stop = True
for a in b:
if stop == True:
break
print(a)
print("Stopped")
You could use multiprocessing.Process to terminate() the process/function my_process_function() whenever you please... Run it as script to get outputs.
import multiprocessing
def my_process_function():
for i in range (100):
print(i)
time.sleep(1)
print("my_process end")
if __name__ == "__main__":
x = multiprocessing.Process(target=my_process_function())
x.start()
print("Stop thread?")
a=input()
if (a=="y"):
x.terminate()
I have a python script that goes like this -
import..
def main ():
some_condition check
main() #calling main again
some condition check
main() #calling main again
main()
The idea here is to let the script run indefinitely and check for something.
This way of calling main() somehow seems incorrect.
I am quite new to Python scripting. Can someone guide me if this very inefficient and if yes then how do I achieve this?
What you are doing is called recursion. This is certainly not good for long running applications, since it would cause a stack overflow.
Do your checking like this:
quit = False
while not quit:
do_your_check()
#maybe sleep
quit = should_i_stop()
Just put the things you want to do in a while true loop.
import ...
def main():
while True:
some_condition check
Recursion is utilized when it is too complex/hard to write as iterative code. e.g. Tree traversals.
Is there an easy way to execute time delay (like time.sleep(3)) between every statement of Python code without having to explicitly write between every statement?
Like in the below Python Script which performs certain action on SAP GUI window. Sometimes, the script continues to the next statement before the previous statement is complete. So, I had to add a time delay between every statement so that it executes correctly. It is working with time delay, but I end up adding time.sleep(3) between every line. Just wondering if there is a better way?
import win32com.client
import time
sapgui = win32com.client.GetObject("SAPGUI").GetScriptingEngine
session = sapgui.FindById("ses[0]")
def add_record(employee_num, start_date, comp_code):
try:
time.sleep(3)
session.findById("wnd[0]/tbar[0]/okcd").text = "/npa40"
time.sleep(3)
session.findById("wnd[0]").sendVKey(0)
time.sleep(3)
session.findById("wnd[0]/usr/ctxtRP50G-PERNR").text = employee_num
time.sleep(3)
session.findById("wnd[0]").sendVKey(0)
time.sleep(3)
session.findById("wnd[0]/usr/ctxtRP50G-EINDA").text = start_date
time.sleep(3)
session.findById("wnd[0]/usr/tblSAPMP50ATC_MENU_EVENT/ctxtRP50G-WERKS[1,0]").text = comp_code
time.sleep(3)
session.findById("wnd[0]/usr/tblSAPMP50ATC_MENU_EVENT/ctxtRP50G-PERSG[2,0]").text = "1"
time.sleep(3)
session.findById("wnd[0]/usr/tblSAPMP50ATC_MENU_EVENT/ctxtRP50G-PERSK[3,0]").text = "U1"
time.sleep(3)
session.findById("wnd[0]/usr/tblSAPMP50ATC_MENU_EVENT").getAbsoluteRow(0).selected = True
time.sleep(3)
return "Pass"
except:
return "failed"
The right way to do what you asked for is almost certainly to use the debugger, pdb.
The right way to do what you want is probably something completely different: find some signal that tells you that the step is done, and wait for that signal. With problems like this, almost any time you pick will be way, way too long 99% of the time, but still too short 1% of the time. That signal may be joining a thread, or waiting on a (threading or multiprocessing) Condition, or getting from a queue, or awaiting a coroutine or future, or setting the sync flag on an AppleEvent, or… It really depends on what you're doing.
But if you really want to do this, you can use settrace:
def sleeper(frame, event, arg):
if event == 'line':
time.sleep(2)
return sleeper
sys.settrace(sleeper)
One small problem is that the notion of line used by the interpreter may well not be what you want. Briefly, a 'line' trace event is triggered whenever the ceval loop jumps to a different lnotab entry (see lnotab_notes.txt in the source to understand what that means—and you'll probably need at least a passing understanding of how bytecode is interpreted, at least from reading over the dis docs, to understand that). So, for example, a multiline expression is a single line; the line of a with statement may appear twice, etc.1
And there's probably an even bigger problem.
Sometimes, the script continues to next step before the previous step is fully complete.
I don't know what those steps are, but if you put the whole thread to sleep for 2 seconds, there's a good chance the step you're waiting for won't make any progress, because the thread is asleep. (For example, you're not looping through any async or GUI event loops, because you're doing nothing at all.) If so, then after 2 seconds, it'll still be just as incomplete as it was before, and you'll have wasted 2 seconds for nothing.
1. If your notion of "line" is closer to what's described in the reference docs on lexing and parsing Python, you could create an import hook that walks the AST and adds an expression statement with a Call to time.sleep(2) after each list element in each body with a module, definition, or compound statement (and then compiles and execs the result as usual).
Anything you want to happen in a program has to be explicitly stated - this is the nature of programming. This is like asking if you can print hello world without calling print("hello world").
I think the best advice to give you here is: don't think in terms of "lines", but think in term of functions.
use debugging mode and watch each and every line executing line by line.
my code is as follow:
done = False
def function():
for loop:
code
if not comply:
done = True #let's say that the code enters this if-statement
while done == False:
function()
For some reason when my code enters the if statement, it doesn't exit the while loop after it's done with function().
BUT, if I code it like this:
done = False
while done == False:
for loop:
code
if not comply:
done = True #let's say that the code enters this if-statement
...it exits the while loop. What's going on here?
I made sure that my code enters the if-statement. I haven't run the debugger yet because my code has a lot of loops (pretty big 2D array) and I gave up on debugging due to it being so tedious. How come "done" isn't being changed when it's in a function?
Your issue is that functions create their own namespace, which means that done within the function is a different one than done in the second example. Use global done to use the first done instead of creating a new one.
def function():
global done
for loop:
code
if not comply:
done = True
An explanation of how to use global can be found here
done=False
def function():
global done
for loop:
code
if not comply:
done = True
you need to use the global keyword to let the interpreter know that you refer to the global variable done, otherwise it's going to create a different one who can only be read in the function.
Use global, only then you can modify a global variable otherwise a statement like done = True inside the function will declare a new local variable named done:
done = False
def function():
global done
for loop:
code
if not comply:
done = True
Read more about the global statement.
Using a class rather than global:
Another way to handle (not use) global variables is to wrap the functions and variables you wish to be global in a class.
While this is a little heavy for this specific case - classes add a host of functionality and flexability to the project. (Personally) highly recommended.
For example:
class Processor():
"""Class container for processing stuff."""
_done = False
def function(self):
"""A function which processes stuff."""
# Some code here ...
self._done = True
# See the flag changing.
proc = Processor()
print('Processing complete:', proc._done)
proc.function()
print('Processing complete:', proc._done)
Output:
Processing complete: False
Processing complete: True