为什么python不等待我的函数完成? [英] Why isn't python waiting for my function to finish?
问题描述
因此,我正在使用tkinter和Python编写一个应用程序以通过串行控制某些设备.在这种情况下,我正在控制恒温槽,并且我有一个简单的功能,等待该恒温槽达到我设定的温度wait_for_temp()
.我以为我在下面包括的control_fcn()
会一直等到bc.wait_for_temp()
调用完成,但是如果只是在control_fcn()
的其余部分中运行.有人知道为什么吗?这是因为我打了app.after()
吗?
So I'm using tkinter and Python to write an app to control some devices over serial. In this case I am controlling a temperature bath and I have a simple function that waits until that bath has reached a temperature I have set called wait_for_temp()
. I thought that control_fcn()
which I've included below would wait until the bc.wait_for_temp()
call completes, but instead if just runs through the rest of the control_fcn()
. Anyone know why? Is this because of my call to app.after()
?
def control_fcn()
bc = Bath_Controller()
# set the temperature I want
set_temp = 16.0
bc.write_temp(set_temp)
print("Commanding temp to " + str(set_temp))
bc.turn_on()
# wait for bath temp to be within .1 of the commanded temp
# this function prints out a "Temperature reached. Carry on." statement when done
bc.wait_for_temp(set_temp)
print("I didn't wait for you friend.")
# in my Bath_Controller() class I have the following function
def wait_for_temp(self, set_temp):
current_temp = self.read_temp()
if (current_temp < set_temp + .05) and (current_temp > set_temp - .05):
print("Temperature reached. Carry on.")
return
else:
print("Waiting for temperature equilibration.\n Current temp is:")
# app here is my root window in tkinter
app.after(10000, lambda: self.wait_for_temp(set_temp))
---更新---
因此,感谢一些有用的答案,我终于有了一种合理且更可维护的方式来等待我的串行设备完成其任务,而又不冻结GUI.我不得不绘制一个小的状态机,但是如果有人好奇,这是我当前的工作代码,涉及更改一些压力阀,更改温度,等待该温度更改,等待用户从管线中取样一些水,以及在多个温度和压力下执行此操作.
So thanks to some helpful answers I've finally gotten a reasonable and more maintainable way to go about waiting for my serial devices to finish their tasks and yet not freeze up the GUI. I had to draw up a little state machine but in case anyone is curious this is my current working code dealing with changing some pressure valves, changing temp, waiting for that temp change, waiting for a user to sample some water from the line, and doing this for multiple temps and pressures.
from collections import deque
def calibrate_master():
bc = Bath_Controller()
vc = Valve_Controller()
sc = Sampling_Controller()
pressure_queue = deque([0, 1, 2, 3, 4, 5])
temp_queue = deque([6, 4, 2])
app.ready_for_pres_change = True # this starts True, and is reset True after last temp and sampling
app.ready_for_temp_change = False # this is set after pres change and after sampling
app.waiting_for_temp = False # this is set true when waiting for temp
app.waiting_for_sample = False # this is set true after temp reached and before sampling is done
calibrate_slave(app, bc, vc, pc, pressure_queue, temp_queue)
def calibrate_slave(app, bc, vc, pc, pressure_queue, temp_queue):
if app.ready_for_pres_change:
vc.set_pressure(pressure_queue.popleft())
app.ready_for_pres_change = False
app.ready_for_temp_change = True
elif app.ready_for_temp_change:
bc.set_temp(temp_queue.popleft())
app.ready_for_temp_change = False
app.waiting_for_temp = True
elif app.waiting_for_temp:
bc.check_temp() # check_temp() will change waiting_for_temp to False and waiting_for_sample to True once temp is met
elif app.waiting_for_sample:
sc.check_sampling() # this checks if the user has pressed a button to indicate sampling complete
if not app.waiting_for_sample:
if temp_queue: # if there are temps left in the temp queue keep running through at same temp
app.ready_for_temp_change = True
elif pressure_queue: # if there are pressures left refill temp queue and move on to next pres
temp_queue = deque([6, 4, 2])
app.ready_for_pres_change = True
else: # if there are not temps and no pressures left the calibration is complete
break
# check back every five seconds
app.after(5000, lambda: calibrate_slave(app, bc, vc, pc, pressure_queue, temp_queue))
推荐答案
它确实等待wait_for_temp
完成.但是,wait_for_temp
几乎立即返回.调用after
不会阻止它返回.恰恰相反,调用after
允许它返回而无需等待.
It does wait for wait_for_temp
to complete. wait_for_temp
will return almost immediately, however. Calling after
doesn't prevent it from returning. Quite the contrary, calling after
allows it to return without waiting.
编写GUI与编写非GUI程序不同. GUI已经处于永久的等待状态.您无需编写本身等待的功能,而需要编写可以响应事件的代码.
Writing a GUI is different from writing non-GUI programs. A GUI is already in a perpetual state of waiting. Instead of writing a function that itself waits, you need to write code that can respond to events.
例如,您可以创建一个<<TemperatureReached>>
事件,当温度达到给定值时可以触发该事件.然后,您可以在事件触发时绑定要调用的函数.
For example, you can create a <<TemperatureReached>>
event that can be triggered when the temperature hits a given value. You can then bind a function to be called when that event triggers.
它看起来像这样:
def control_fcn()
bc = Bath_Controller()
# set the temperature I want
set_temp = 16.0
bc.write_temp(set_temp)
# arrange for notifyUser to be called when the target
# temperature has been reached
app.bind("<<TemperatureReached>>", self.notifyUser)
# periodically check the temp
self.check_temp(set_temp)
def notifyUser(event):
print("Temperature reached")
def check_temp(self, set_temp):
current_temp = self.read_temp()
if (current_temp < set_temp + .05) and (current_temp > set_temp - .05):
# temperature reached; send an event
app.event_generate("<<TemperatureReached>>")
else:
# temperature not reached. Check again in 10 seconds
app.after(10000, self.check_temp, set_temp)
这篇关于为什么python不等待我的函数完成?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!