Как завершить скрипт Python


1079

Мне известна die()команда в PHP, которая рано выходит из скрипта.

Как я могу сделать это в Python?

Ответы:


1418
import sys
sys.exit()

детали из sysдокументации модуля :

sys.exit([arg])

Выход из Python. Это реализуется путем вызова SystemExitисключения, поэтому действия по очистке, указанные в предложениях finally, tryвыполняются, и можно перехватить попытку выхода на внешнем уровне.

Необязательный аргумент arg может быть целым числом, указывающим статус выхода (по умолчанию равен нулю), или объектом другого типа. Если это целое число, ноль считается «успешным завершением», а любое ненулевое значение считается «ненормальным завершением» в оболочках и т.п. Большинство систем требуют, чтобы он находился в диапазоне 0-127, и в противном случае дают неопределенные результаты. В некоторых системах есть соглашение о назначении определенных значений определенным кодам выхода, но они обычно недостаточно развиты; Программы Unix обычно используют 2 для ошибок синтаксиса командной строки и 1 для всех других видов ошибок. Если передается объект другого типа, None эквивалентен пропусканию нуля, а любой другой объект печатается в stderrи приводит к коду выхода 1. В частности, sys.exit("some error message") быстрый способ выхода из программы при возникновении ошибки.

Поскольку в exit()конечном итоге «only» вызывает исключение, оно будет выходить из процесса только при вызове из основного потока, и исключение не перехватывается.

Обратите внимание, что это «хороший» способ выхода. @ glyphtwistedmatrix ниже указывает на то, что если вы хотите «жесткий выход», вы можете использовать его os._exit(*errorcode*), хотя он, вероятно, в некоторой степени специфичен для ОС (например, он может не принимать код ошибки в Windows) и определенно менее дружественен, так как не позволяет переводчику выполнять очистку до того, как процесс завершится.


9
Предположительно sys.exit(), не работает (не убивает процесс, просто убивает поток), если вызвано фоновым потоком?

@ caesium62: Да, sys.exit()возникает SystemExitисключение в текущей теме.
Дмитрий Трофимов

13
Есть ли способ завершить сценарий, не вызывая исключения? Я уже передаю соответствующие флаги из сценария с выводом на печать в стандартный поток сообщений в Popen, поэтому исключение в этом случае создает больше проблем, чем решает.
Эллиот

4
Почему, когда я использую этот метод, я получаю следующее предупреждение:UserWarning: To exit: use 'exit', 'quit', or Ctrl-D. warn("To exit: use 'exit', 'quit', or Ctrl-D.", stacklevel=1)
Билл

1
Нужно больше деталей; может быть, это заслуживает отдельного вопроса?
pjz

349

Простой способ досрочного завершения скрипта Python - это использование встроенной quit()функции. Там нет необходимости импортировать любую библиотеку, и это эффективно и просто.

Пример:

#do stuff
if this == that:
  quit()

86
также sys.exit () завершит все сценарии Python, но quit () завершит только сценарий, который его породил.
VishalDevgire

4
Знаете ли вы, если эта команда работает по-разному в Python 2 и Python 3?
Дэвид С.

1
Кто-нибудь знает, выйдет ли из этого весь интерпретатор или просто остановит выполнение скрипта? В частности: для скрипта, работающего в Spyder, интерпретатор Python останется интерактивным, или он будет убит? Попытайтесь просто остановить продолжение сценария, но оставьте интерактивность интерпретатора присутствующей.
Демис

3
для меня это говорит «выйти» не определено. Я использую Python 3.
Vincenzooo

4
Я в Python 3.7 и quit () останавливает интерпретатор и закрывает скрипт.
RockAndRoleCoder

120

Другой способ это:

raise SystemExit

36
@Alessa: выглядит более элегантно, но не рекомендуется: вы напрямую sys.exit
вызываете

1
Это идеальный способ для меня: просто выйдите из работающего скрипта, но не
выходите

78

Вы также можете использовать просто exit().

Имейте в виду , что sys.exit(), exit(), quit()и os._exit(0) убить интерпретатор Python. Следовательно, если он появляется в сценарии, вызванном из другого сценария execfile(), он останавливает выполнение обоих сценариев.

Смотрите « Остановите выполнение скрипта, вызванного с execfile », чтобы избежать этого.


67

Хотя вы, как правило, предпочитаете, sys.exitпотому что он более «дружественный» по отношению к другому коду, все, что он на самом деле делает, это вызывает исключение.

Если вы уверены, что вам нужно немедленно выйти из процесса, и вы можете оказаться в каком-то обработчике исключений, который будет перехватывать SystemExit, есть другая функция, os._exitкоторая немедленно завершается на уровне C и не выполняет никакого обычного завершения. переводчика; например, хуки, зарегистрированные в модуле "atexit", не выполняются.


43

Я только что узнал, что при написании многопоточного приложения, raise SystemExitи sys.exit()оба убивают только работающий поток. С другой стороны, os._exit()выходит весь процесс. Это обсуждалось в разделе « Почему sys.exit () не завершается при вызове внутри потока в Python? ».

Пример ниже имеет 2 потока. Кенни и Картман. Картман должен жить вечно, но Кенни вызывается рекурсивно и должен умереть через 3 секунды. (рекурсивный вызов не лучший способ, но у меня были другие причины)

Если мы также хотим, чтобы Картман умер, когда умрет Кенни, Кенни должен уйти os._exit, иначе умрет только Кенни, и Картман будет жить вечно.

import threading
import time
import sys
import os

def kenny(num=0):
    if num > 3:
        # print("Kenny dies now...")
        # raise SystemExit #Kenny will die, but Cartman will live forever
        # sys.exit(1) #Same as above

        print("Kenny dies and also kills Cartman!")
        os._exit(1)
    while True:
        print("Kenny lives: {0}".format(num))
        time.sleep(1)
        num += 1
        kenny(num)

def cartman():
    i = 0
    while True:
        print("Cartman lives: {0}".format(i))
        i += 1
        time.sleep(1)

if __name__ == '__main__':
    daemon_kenny = threading.Thread(name='kenny', target=kenny)
    daemon_cartman = threading.Thread(name='cartman', target=cartman)
    daemon_kenny.setDaemon(True)
    daemon_cartman.setDaemon(True)

    daemon_kenny.start()
    daemon_cartman.start()
    daemon_kenny.join()
    daemon_cartman.join()

1
Кажется, это единственный способ справиться с отвратительно отложенными обратными вызовами! (т.е. многопоточные методы.)
not2qubit

1
Отлично сработано. Ни один из других ответов напрямую не касается нескольких потоков, только сценарии, порождающие другие сценарии.
анонимно

33
from sys import exit
exit()

В качестве параметра вы можете передать код выхода, который будет возвращен в ОС. По умолчанию 0.


3
в моем случае мне даже не нужно было импортировать выход.
Костанос

5
Просто для потомков на вышеприведенный комментарий - exit()и sys.exit()это не одно и то же. Не используйте встроенные exit()скрипты, это всего лишь помощник для интерактивной оболочки - используйтеsys.exit()
daveruinseverything

18

Я новичок, но, конечно, это чище и более контролируемо

def main():
    try:
        Answer = 1/0
        print  Answer
    except:
        print 'Program terminated'
        return
    print 'You wont see this'

if __name__ == '__main__': 
    main()

...

Программа прекращена

чем

import sys
def main():
    try:
        Answer = 1/0
        print  Answer
    except:
        print 'Program terminated'
        sys.exit()
    print 'You wont see this'

if __name__ == '__main__': 
    main()

...

Программа завершила трассировку (последний вызов был последним): файл "Z: \ Directory \ testdieprogram.py", строка 12, в main () Файл "Z: \ Directory \ testdieprogram.py", строка 8, в основном sys.exit ( ) SystemExit

редактировать

Дело в том, что программа заканчивается гладко и мирно, а не "Я ОСТАНОВЛЕН !!!!"


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

11
Это абсолютная чепуха, если вы пытаетесь предложить, что вы можете использовать returnдля завершения сценария. Все, что returnнужно сделать, это вернуть значение и поток управления вызывающей функции. Там он продолжает выполнение сразу после вызова функции, которая вызвала return. Конечно, если returnпоследний оператор в вашем сценарии, как в вашем примере, сценарий завершается сразу после его вызова.
Давид Ференци Рогожан

1
Для этого подхода необходимо сделать веские аргументы: (1) «выход» из середины, возможно, является «goto», следовательно, естественным отвращением; (2) «выход» в библиотеках - определенно плохая практика (и все может стать библиотекой), поскольку то, что библиотека считает «неустранимым», обычно прекрасно для вызывающей стороны . (Примечание: использование исключений для выходов - это практический обход Python для разработчиков C / C ++ / Java, всегда вызывающих ненадлежащим образом exit- следовательно, программисты на python могут не заметить запах этого кода так сильно); и, наконец, (3) многопоточный код (который питонисты исторически просто игнорировали).
Майкл

8

В Python 3.5 я пытался включить подобный код без использования модулей (например, sys, Biopy), кроме встроенных, чтобы остановить скрипт и вывести сообщение об ошибке моим пользователям. Вот мой пример:

## My example:
if "ATG" in my_DNA: 
    ## <Do something & proceed...>
else: 
    print("Start codon is missing! Check your DNA sequence!")
    exit() ## as most folks said above

Позже я обнаружил, что более кратким является просто выдать ошибку:

## My example revised:
if "ATG" in my_DNA: 
    ## <Do something & proceed...>
else: 
    raise ValueError("Start codon is missing! Check your DNA sequence!")

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

-1

Мои два цента.

Python 3.8.1, Windows 10, 64-битная.

sys.exit() не работает напрямую для меня.

У меня есть несколько следующих петель.

Сначала я объявляю логическую переменную, которую я вызываю immediateExit.

Итак, в начале кода программы я пишу:

immediateExit = False

Затем, начиная с самого внутреннего (вложенного) цикла, я пишу:

            immediateExit = True
            sys.exit('CSV file corrupted 0.')

Затем я перехожу к непосредственному продолжению внешнего цикла и, прежде чем что-либо еще, выполняемое кодом, напишу:

    if immediateExit:
        sys.exit('CSV file corrupted 1.')

В зависимости от сложности, иногда вышеупомянутое утверждение необходимо повторять также в разделах и т. Д.

    if immediateExit:
        sys.exit('CSV file corrupted 1.5.')

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

'CSV file corrupted 1.5.'

В моем конкретном случае я обрабатываю файл CSV, который я не хочу, чтобы программное обеспечение касалось, если оно обнаруживает, что оно повреждено. Поэтому для меня очень важно выйти из всего скрипта Python сразу после обнаружения возможного повреждения.

И после постепенного выхода из всех циклов мне удается это сделать.

Полный код: (некоторые изменения были необходимы, потому что это собственный код для внутренних задач):

immediateExit = False
start_date = '1994.01.01'
end_date = '1994.01.04'
resumedDate = end_date


end_date_in_working_days = False
while not end_date_in_working_days:
    try:
        end_day_position = working_days.index(end_date)

        end_date_in_working_days = True
    except ValueError: # try statement from end_date in workdays check
        print(current_date_and_time())
        end_date = input('>> {} is not in the list of working days. Change the date (YYYY.MM.DD): '.format(end_date))
        print('New end date: ', end_date, '\n')
        continue


    csv_filename = 'test.csv'
    csv_headers = 'date,rate,brand\n' # not real headers, this is just for example
    try:
        with open(csv_filename, 'r') as file:
            print('***\nOld file {} found. Resuming the file by re-processing the last date lines.\nThey shall be deleted and re-processed.\n***\n'.format(csv_filename))
            last_line = file.readlines()[-1]
            start_date = last_line.split(',')[0] # assigning the start date to be the last like date.
            resumedDate = start_date

            if last_line == csv_headers:
                pass
            elif start_date not in working_days:
                print('***\n\n{} file might be corrupted. Erase or edit the file to continue.\n***'.format(csv_filename))
                immediateExit = True
                sys.exit('CSV file corrupted 0.')
            else:
                start_date = last_line.split(',')[0] # assigning the start date to be the last like date.
                print('\nLast date:', start_date)
                file.seek(0) # setting the cursor at the beginnning of the file
                lines = file.readlines() # reading the file contents into a list
                count = 0 # nr. of lines with last date
                for line in lines: #cycling through the lines of the file
                    if line.split(',')[0] == start_date: # cycle for counting the lines with last date in it.
                        count = count + 1
        if immediateExit:
            sys.exit('CSV file corrupted 1.')
        for iter in range(count): # removing the lines with last date
            lines.pop()
        print('\n{} lines removed from date: {} in {} file'.format(count, start_date, csv_filename))



        if immediateExit:
            sys.exit('CSV file corrupted 1.2.')
        with open(csv_filename, 'w') as file:
            print('\nFile', csv_filename, 'open for writing')
            file.writelines(lines)

            print('\nRemoving', count, 'lines from', csv_filename)

        fileExists = True

    except:
        if immediateExit:
            sys.exit('CSV file corrupted 1.5.')
        with open(csv_filename, 'w') as file:
            file.write(csv_headers)
            fileExists = False
    if immediateExit:
        sys.exit('CSV file corrupted 2.')

1
Спасибо за ваш вклад, но для меня этот ответ не имеет смысла. Поскольку вы публикуете только несколько фрагментов кода вместо полного примера, трудно понять, что вы имеете в виду. При наличии только тех строк кода, которые вы разместили здесь, скрипт немедленно завершится. Я могу только догадываться, что у вас есть блок try-catch, который перехватывает исключение SystemExit, которое уже упоминалось в других ответах. Если бы вы переписали свой ответ с полным рабочим примером того, как вы могли бы чисто выйти из приложения (то есть, выполнив некоторые необходимые действия по завершению работы), я думаю, что ваш пост может быть полезным дополнением.
wovano

Спасибо за ваш отзыв. Теперь я добавил ту часть кода, которая касается операторов выхода.
Мэтью

Хорошо, это дает немного больше контекста :) Хотя сейчас я думаю, что ваше решение - это обходной путь для очень плохих шаблонов программирования. Прежде всего, вы никогда не должны использовать except:без исключений типа. Если вы просто используете except Exception:(или даже более подробный тип исключения, если это возможно), он sys.exit()будет работать как задумано, и вам не понадобится этот обходной путь.
wovano

Во-вторых, кажется, что вы пытаетесь сделать целый ряд вещей в одном методе, или, возможно, даже в глобальной области файлов. Это поможет разбить ваш код на более мелкие части (функции), например: (1) загрузить входной файл, (2) обработать данные и (3) записать выходной файл. Затем, если шаг 1 завершится неудачно, вы пропустите шаги 2 и 3. Вы можете вызвать исключение в любом месте на этапе загрузки и обработать исключение в одном месте. Использование sys.exit()действительно своего рода последнее средство для решения критических ошибок. Просто мои два цента :)
wovano

В общем, я не вижу глобальной функции выхода / остановки в Python, и я вынужден сделать это таким образом. Файл CSV действительно важен для меня, поэтому я стараюсь его всеми силами, даже если средства могут выглядеть уродливо. Я читаю Руководство Hichhicker по Python, чтобы улучшить свой стиль.
Мэтью
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.