I am a Python noob, and I'm trying to make a washing device, programming the interface with Python. For now, the machine should work like that:
Wash
Tell washing is complete
Dry
Tell drying is complete
For this, after times for washing/drying are entered, a button is pressed:
button1 = Button(window.tk, command = lambda:main_process(int(varWashtime.get()), int(varDrytime.get())))
def main_process(wash_seconds,dry_seconds):
wash(wash_seconds)
stop_wash()
dry(dry_seconds)
stop_dry()
return
def wash(seconds):
varWashStarted.set("Washing Started")
Timer(seconds,idle_fnc).start()
return
def stop_wash():
varWashStarted.set("Washing Stopped")
Timer(3,idle_fnc,()).start()
return
def dry(seconds):
varDryStarted.set("Drying Started")
Timer(seconds,idle_fnc,()).start()
return
def stop_dry():
varDryStarted.set("Drying Stopped")
return
def idle_fnc():
pass
return
Here, I used the function idle_fnc to make threading.Timer properly work.
I found out that I can just use Timer to call other functions after each other, but I would prefer to return from a function, then branch to a new one.
My problem is, as I click the button, the whole thing executes without waiting; I instantly see "Washing Stopped" and "Drying Stopped" on the corresponding label, without the delays triggered.
What is the problem?
Related
I am trying to write a CUI app where the window is supposed to flash after returning from a customized infunction. This would make it so that the flashing occurs after the input prompt is displayed, not beforehand.
My first idea was:
from ctypes import windll
def custom_formatted_input():
while get_foreground_window_title() != "cmd.exe":
windll.user32.FlashWindow(windll.kernel32.GetConsoleWindow(), True)
time.sleep(0.5)
return input(f"""{time.strftime("%Y-%m-%d %H:%M:%S")}{"".ljust(4)}[INPUT]{"".ljust(6)}{message} """)
where get_foreground_window_title is a Windows API call through ctypes.
This works, however this makes it so the input prompt is displayed whenever the flashing stops, i.e. after the user activates the cmd window.
How can I make it so that this flashing happens after the input function returns? I believe this would entail a decorator, however I couldn't figure the solution out on my own. Thanks!
Figured it out! Since execution always stops whenever input() is called, the flashing needs to occur while the execution is stopped, i.e. on another thread.
Code:
def flash_window():
while "cmd.exe" not in get_foreground_window_title():
windll.user32.FlashWindow(windll.kernel32.GetConsoleWindow(), True)
time.sleep(0.5)
def input_log(message):
t1 = threading.Thread(target=flash_window)
t1.start()
return input(f"""{time.strftime("%Y-%m-%d %H:%M:%S")}{"".ljust(4)}[INPUT]{"".ljust(6)}{message} """)
Please, accept my apologies for the delayed feedback. It was impossible before.
I'll explain it better.
I've built a Midi - OSC control surface for Reaper in Python. It receives and sends OSC messages.
I use UP and DOWN arrows on the keyboard to move through tracks in Reaper. I can move very fast through tracks until I find the one I want to stay on. Then, my script sends a OSC message to receive everything from Reaper using PythonOSC.
I will explain using code.
That function receives OSC messages (e.g.: /track/volume, etc.) Each time the client receives /select, it tells my script that a track changed in Reaper.
def OSC(self, *args):
s = re.search(r'/track/(.+)', args[0])
if s:
if s.group(1) == 'select' and args[1] == 0:
"""I want that next line to be executed only when about 0.5 second had passed
since the last time it enters that point. It is to avoid that PythonOSC sends
that line 10 times in 1 second and overloads the process."""
client.send_message('/device/track/follows/last_touched', 1)
I imagined something like that but I don't know if it's overkill, if I miss something.
Each time I press up or down, a timer starts in a thread or something. It resets each time.
When I land on my track, the timer continues until 0.5 second and then, launches my client.send_message() line.
Is it too much? The thing is, a thread will still have to be killed or something. I'm very new to Python.
The example given, with the decorator is great but it activates the function (in my case, it's finally only a line of code) when it's triggred within 0.5 second while I want it to be triggered after a 0.5 second pause following the last time it's called.
Note: I realize that my code example is all sent in a block in the preview box. I indented it but it breaks it. I'm very sorry for that, I can't see the option I need to use.
I'm not sure that I've interpreted your question correctly, but if you're trying to make function execution to take not less than provided time, you can use this decorator
from time import time, sleep
def timed(time_to_sleep):
def decorator(function):
def wrapper(*args, **kwargs):
start_time = time()
result = function(*args, **kwargs)
time_to_sleep_left = time_to_sleep - (time() - start_time)
if time_to_sleep_left > 0:
sleep(time_to_sleep_left)
return result
return wrapper
return decorator
Usage:
#timed(0.5)
def test():
pass
All programs which I see in tutorials are console and code is executed from first line to the last line and if there is while everything starts from the first line. Is there any way for console programs to change their execution way, due to some event, like e.g. key press or some event in code? The best example of what I want to do is router CLI. Where can I find such examples?
def main():
while(True):
initial_setup() #choose IPs to monitor
while(True):
do_some_work() # do monitor the IPs
I need some listener in the secons while which detects keypresses and then I go to initial setup, meanwhile do_some_work works and only after I finish adittional changes in initial_setup do_some_work restarts.
Sorry I am noob and not very good in explaining probaly because English is not native for me. The best example from real life I can name is CLI of router, you can setup intreface and meanwhile router do routing in the background.
Code for Sergio S:
import threading
import time
def hello():
while(True):
print("Hello")
time.sleep(2)
def hi():
while(True):
print("hi")
time.sleep(2)
def press_key():
a=input()
a=False
return a
def circle():
MrBoolean=True
while(MrBoolean):
thr=[]
thr.append(threading.Thread(target=hello))
thr.append(threading.Thread(target=hi))
thr.append(threading.Thread(target=press_key))
for i in thr:
i.start()
for i in thr:
i.join()
mrBoolean=thr[3]
def main():
while(True):
circle()
main()
From your description, it seems you're searching for something called multithreading: while one part of the application does one thing, the other does something else. See these other questions for more details: How to use threading in Python? , How to stop a looping thread in Python?
whats_typed = input('Say Aah:')
if whats_typed.strip() == 'Aah':
print('Thanks!')
else:
print('Whoops. Your input was:', whats_typed)
The above changes what is executed depending on user input when the program is run.
I am learning how to use pyobjc for some basic prototyping. Right now I have a main UI set up and a python script that runs the main application. The only issue is when the script runs, the script runs on the main thread thus blocking the UI.
So this is my sample code snippet in that I attempted in python using the threading import:
def someFunc(self):
i = 0
while i < 20:
NSLog(u"Hello I am in someFunc")
i = i + 1
#objc.IBAction
def buttonPress(self, sender):
thread = threading.Thread(target=self.threadedFunc)
thread.start()
def threadedFunc(self):
NSLog(u"Entered threadedFunc")
self.t = NSTimer.NSTimer.scheduledTimerWithTimeInterval_target_selector_userInfo_repeats_(1/150., self,self.someFunc,None, True)
NSLog(u"Kicked off Runloop")
NSRunLoop.currentRunLoop().addTimer_forMode_(self.t,NSDefaultRunLoopMode)
When clicking on the button, the NSLogs in threadedFunc prints out to console, but it never enters someFunc
So I decided to use NSThread to kick off a thread. On Apple's documentation the Objective-C call looks like this:
(void)detachNewThreadSelector:(SEL)aSelector
toTarget:(id)aTarget
withObject:(id)anArgument
So I translated that to what I interpreted as pyobjc rules for calling objective-c function:
detachNewThreadSelector_aSelector_aTarget_anArgument_(self.threadedFunc, self, 1)
So in context the IBAction function looks like this:
#objc.IBAction
def buttonPress(self, sender):
detachNewThreadSelector_aSelector_aTarget_anArgument_(self.threadedFunc, self, 1)
But when the button is pressed, I get this message: global name 'detachNewThreadSelector_aSelector_aTarget_anArgument_' is not defined.
I've also tried similar attempts with grand central dispatch, but the same message kept popping up of global name some_grand_central_function is not defined
Clearly I am not understanding the nuances of python thread, or the pyobjc calling conventions, I was wondering if some one could shed some light on how to proceed.
So I got the result that I wanted following the structure below. Like I stated in my response to the comments: For background thread, NSThread will not allow you to perform certain tasks. (i.e update certain UI elements, prints, etc). So I used performSelectorOnMainThread_withObject_waitUntilDone_ for things that I needed to perform in between thread operations. The operations were short and not intensive so it didn't affect the performance as much. Thank you Michiel Kauw-A-Tjoe for pointing me in the right direction!
def someFunc(self):
i = 0
someSelector = objc.selector(self.someSelector, signature='v#:')
while i < 20:
self.performSelectorOnMainThread_withObject_waitUntilDone(someSelector, None, False)
NSLog(u"Hello I am in someFunc")
i = i + 1
#objc.IBAction
def buttonPress(self, sender):
NSThread.detachNewThreadSelector_toTarget_withObject_(self.threadedFunc, self, 1)
def threadedFunc(self):
NSLog(u"Entered threadedFunc")
self.t = NSTimer.NSTimer.scheduledTimerWithTimeInterval_target_selector_userInfo_repeats_(1/150., self,self.someFunc,None, True)
NSLog(u"Kicked off Runloop")
self.t.fire()
The translated function name should be
detachNewThreadSelector_toTarget_withObject_(aSelector, aTarget, anArgument)
You're currently applying the conversion rule to the arguments part instead of the Objective-C call parts. Calling the function with the arguments from your example:
detachNewThreadSelector_toTarget_withObject_(self.threadedFunc, self, 1)
When I make text adventures in python for my friends, I am constantly frustrated that I have to code the adventure upward since python reads code from top to bottom. For example:
def stage2():
def stage1():
def start():
Then so on and so forth.. Is there any way that I can make python read the code in a different way so that I can code text adventures from the top up?
You can write your functions in whatever order you like, so long as they are defined before they are called.
For instance,
def start():
print("Welcome to the adventure")
stage1()
def stage1():
print("You made it this far!")
stage2()
# if you called start() here,
# you would have an error when stage1() tries to call stage2(),
# because the interpreter doesn't know what a stage2 is yet.
def stage2():
print("Oops - you died.")
start()
works fine.
On the other side of things:
def test():
if True:
print("Yup")
else:
slartibartfast()
test()
runs fine because the interpreter never gets around to asking what a slartibartfast is ;-)