Как выйти из цикла while только после завершения текущего цикла в Python?

Я пытаюсь настроить свой скрипт Python, чтобы пользователь мог завершить программу, однако программа должна сначала завершить то, что она делает. У меня настроен следующий код:

import sys
import keyboard
import time

prepareToStop = 0;
try:
    while prepareToStop == 0:
        #Program code here
        print(prepareToStop)
        time.sleep(0.1)
except KeyboardInterrupt:
    prepareToStop = 1
    print("\nProgram will shut down after current operation is complete.\n")

print("Program shutting down...")
sys.exit()

Однако программа по-прежнему выходит из цикла, как только получено сообщение KeyboardInterrupt. Я видел совет, что это можно исправить, поместив «попробовать, кроме» внутри цикла while, однако это приводит к тому, что программа вообще не может обнаружить KeyboardInterrupt.

Перемещение try/кроме внутри while сработало для меня. Я запускаю линукс. Его возможные Windows отличаются.

tdelaney 15.02.2023 17:37

Я попробовал это с помощью Windows, и решение @tdelaney работает

Skapis9999 15.02.2023 17:40

Ваш цикл while не завершится, так как в вашем операторе try нет ошибки. Вам нужен оператор выхода в цикле while или просто переместите оператор try внутри цикла while, как сказал @tdelaney

Pruthvi 15.02.2023 17:42

@Pruthvi - Идея состоит в том, что пользователь нажимает ctrl-c для создания прерывания клавиатуры.

tdelaney 15.02.2023 17:44

Независимо от того, где вы поместите try-except, KeyboardInterrupt прервет по крайней мере часть вашего кода. Вам нужно будет использовать модуль signal, чтобы заменить генерацию этого исключения установкой флага prepareToStop.

jasonharper 15.02.2023 17:45

@tdelaney Я переместил try/except во время, но результат был тот же. Я также обнаружил, что если я удаляю строку «prepareToStop = 1», цикл начинается сначала, когда срабатывает KeyboardInterrupt. Я думаю, что это настоящая причина проблемы, но я все еще не уверен, как это предотвратить.

Straxan 15.02.2023 17:48

Print(prepareToStop) ничего вам не скажет, потому что вы делаете это сразу после того, как проверите, что это 0.

Mark Ransom 15.02.2023 17:52
Инструменты для веб-скрапинга с открытым исходным кодом: Python Developer Toolkit
Инструменты для веб-скрапинга с открытым исходным кодом: Python Developer Toolkit
Веб-скрейпинг, как мы все знаем, это дисциплина, которая развивается с течением времени. Появляются все более сложные средства борьбы с ботами, а...
Библиотека для работы с мороженым
Библиотека для работы с мороженым
Лично я попрощался с операторами print() в python. Без шуток.
Эмиссия счетов-фактур с помощью Telegram - Python RPA (BotCity)
Эмиссия счетов-фактур с помощью Telegram - Python RPA (BotCity)
Привет, люди RPA, это снова я и я несу подарки! В очередном моем приключении о том, как создавать ботов для облегчения рутины. Вот, думаю, стоит...
Пошаговое руководство по созданию собственного Slackbot: От установки до развертывания
Пошаговое руководство по созданию собственного Slackbot: От установки до развертывания
Шаг 1: Создание приложения Slack Чтобы создать Slackbot, вам необходимо создать приложение Slack. Войдите в свою учетную запись Slack и перейдите на...
Учебник по веб-скрапингу
Учебник по веб-скрапингу
Привет, ребята... В этот раз мы поговорим о веб-скрейпинге. Целью этого обсуждения будет узнать и понять, что такое веб-скрейпинг, а также узнать, как...
Тонкая настройка GPT-3 с помощью Anaconda
Тонкая настройка GPT-3 с помощью Anaconda
Зарегистрируйте аккаунт Open ai, а затем получите ключ API ниже.
0
7
54
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Если я правильно понимаю вашу проблему, возможно, вам поможет threading. Обратите внимание, как end do something появляется даже после KeyboardInterrupt.

Обновлено: я поместил t.join() в try

import sys
import time
import threading

def do_something(prepareToStop):
    print(prepareToStop)
    time.sleep(1)
    print('end do something')

prepareToStop = 0
while prepareToStop == 0:
    t = threading.Thread(target=do_something, args=[prepareToStop])
    try:
        t.start()
        t.join() # wait for the threading task to end
    except KeyboardInterrupt:
        prepareToStop = 1
        print("\nProgram will shut down after current operation is complete.\n")
    print('will not appear for last run')

print("Program shutting down...")
sys.exit()

Пример вывода:

0
end do something
will not appear for last run
0
^C
Program will shut down after current operation is complete.

will not appear for last run
Program shutting down...

end do something

Попробуйте еще раз с моим Edit: t.join() в разделе try лучше

Phoenixo 15.02.2023 17:59

Прерывание клавиатуры, которое вы пытались использовать, работает как любое системное прерывание и немедленно переходит к блоку исключений, не возвращаясь туда, где оно было, когда произошло прерывание. Вы можете убедиться в этом, используя отладчик в вашей среде IDE (например, нажмите F5 в VSCODE).

Приведенный ниже код работает так, как вы хотите, но пользователь должен удерживать нажатой клавишу ESC на клавиатуре, чтобы он был захвачен из программы в нужное время.

import sys
import keyboard
import time

prepareToStop = 0;

while prepareToStop == 0:
    if keyboard.is_pressed('Esc'):
        prepareToStop = 1
        print("\nProgram will shut down after current operation is complete.\n")
    #Program code here
    print('Sleeping 5 sec - hold the ESC key for some time to exit')
    time.sleep(5)
    print('This prints only after the delay')
    #end code here
    print(prepareToStop)
    time.sleep(0.1)
        
print("Program shutting down...")
sys.exit()

И тогда я бы рекомендовал изменить на это:

import sys
import keyboard
import time


while not keyboard.is_pressed('Esc'):
    #Program code here
    print('Sleeping 5 sec - hold the ESC key for some time to exit')
    time.sleep(5)
    print('This prints only after the delay')
    #end code here
    time.sleep(0.1)
        
print("Program shutting down...")
sys.exit()

Приведенное выше решение не лучше, чем использование потоков, но оно намного проще.

Другие вопросы по теме