Почему Python не ждет завершения моей функции?

Поэтому я использую tkinter и Python для записи приложения для управления некоторыми устройствами через последовательный порт. В этом случае я контролирую температурную ванну, и у меня есть простая функция, которая ждет, пока эта ванна не достигнет температуры, установленной мною wait_for_temp() . Я думал, что control_fcn() который я включил ниже, будет ждать, пока bc.wait_for_temp() завершится, но вместо этого, если он просто control_fcn() через оставшуюся часть control_fcn() . Кто-нибудь знает, почему? Это из-за моего вызова 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)) 

— ОБНОВИТЬ —

Поэтому, благодаря некоторым полезным ответам, я наконец получил разумный и более удобный способ, чтобы ждать, когда мои последовательные устройства закончат свои задачи и не заморозят графический интерфейс. Мне пришлось составлять небольшую государственную машину, но в случае, если кому-то это интересно, это мой текущий рабочий код, касающийся изменения некоторых клапанов давления, изменения температуры, ожидания изменения темпа, ожидания пользователя, чтобы пробовать воду из линии, и делая это для нескольких темпов и давлений.

 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 позволяет ему вернуться без ожидания.

    Написание графического интерфейса отличается от написания программ, отличных от GUI. Графический интерфейс уже находится в постоянном состоянии ожидания. Вместо того, чтобы писать функцию, которая сама ждет, вам нужно написать код, который может реагировать на события.

    Например, вы можете создать событие <<TemperatureReached>> которое может быть вызвано, когда температура достигнет заданного значения. Затем вы можете связать функцию, вызываемую при срабатывании этого события.

    Это будет выглядеть примерно так:

     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) 

    Метод after предназначен для немедленного возврата. Точка использования через некоторое while True: цикл заключается в том, что он немедленно возвращается и не блокирует GUI. Чтобы получить то, что вы хотите, вам придется разделить его:

     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) def done(): 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.") done() 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)) 

    В app.after() вы в основном говорите, что запустите этот кусок кода через 10 секунд, однако вы не поручаете процессору wait 10 seconds в соединении.

    Простое решение состоит в том, чтобы обернуть вашу функцию wait_for_temp() в правильном while loop и подождать, пока вы не получите желаемый результат, то есть:

     # in my Bath_Controller() class I have the following function def wait_for_temp(self, set_temp): while 1: current_temp = self.read_temp() if (current_temp < set_temp + .05) and (current_temp > set_temp - .05): print("Temperature reached. Carry on.") return time.sleep(1)