Як закінчити сценарій Python


1076

Мені відомо про die()команду в PHP, яка закриває сценарій рано.

Як я можу це зробити в Python?

Відповіді:


1416
import sys
sys.exit()

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

sys.exit([arg])

Вихід з Python. Це реалізується шляхом підняття SystemExitвинятку, тому дії очищення, визначені остаточно пунктами tryтверджень, шануються, і можлива перехоплення спроби виходу на зовнішній рівень.

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

Оскільки в exit()кінцевому підсумку "тільки" викликає виняток, він вийде з процесу лише тоді, коли викликається з основного потоку, і виняток не перехоплюється.

Зауважте, що це "приємний" спосіб виходу. @ glyphtwistedmatrix нижче вказує, що якщо ви хочете "важкий вихід", ви можете використовувати os._exit(*errorcode*), хоча це певна ос-специфічна до певної міри (можливо, це не може прийняти код помилки під Windows, наприклад), і це, безумовно, менш дружнє, оскільки це не дозволяє перекладачеві робити будь-яку очистку до того, як процес загине.


9
Імовірно sys.exit(), не працює (не вбиває процес, просто вбиває нитку), якщо піднята фоновою ниткою?

@ cesium62: Так, sys.exit()викликає SystemExitвиняток у поточному потоці.
Дмитро Трофімов

13
Чи є спосіб закінчити сценарій без винятку? Я вже передаю відповідні прапорці зі сценарію з друком, щоб stdout проходив у 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
Це ідеальний спосіб для мене: просто вийдіть із запущеного сценарію, але не виходьте з IDLE
rml

77

Ви також можете використовувати просто exit().

Майте на увазі , що sys.exit(), exit(), quit()і os._exit(0) вбити інтерпретатор Python. Тому, якщо він з'являється у скрипті, викликаному з іншого сценарію execfile(), він зупиняє виконання обох сценаріїв.

Див. " Зупинення виконання сценарію, викликаного execfile ", щоб уникнути цього.


67

Хоча ви, як правило, віддаєте перевагу sys.exitтому, що він більш "привітний" до іншого коду, все, що він насправді робить, - це виняток.

Якщо ви впевнені, що вам потрібно негайно вийти з процесу, і ви можете опинитися в якомусь обробнику винятків, який міг би наздогнати SystemExit, є ще одна функція - os._exit- яка припиняється негайно на рівні С і не виконує жодної нормальної руйнування перекладача; наприклад, гачки, зареєстровані модулем "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()

...

Програма завершена Traceback (останній дзвінок останній): Файл "Z: \ Каталог \ testdieprogram.py", рядок 12, в main () Файл "Z: \ Каталог \ testdieprogram.py", рядок 8, в основному sys.exit ( ) SystemExit

Редагувати

Справа в тому, що програма закінчується плавно і мирно, а не "Я зупинився !!!!"


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

11
Це абсолютна дурниця, якщо ви намагаєтесь запропонувати, що ви можете використовувати returnдля припинення сценарію. Все, що returnробиться - це повернення значення і потік управління функції виклику. Там він продовжується із виконанням відразу після виклику функції, яка викликала return. Звичайно, якщо returnостаннє твердження у вашому сценарії, як у вашому прикладі, то сценарій припиняється відразу після його виклику.
Девід Ференці Рогожан

1
Для цього підходу слід зробити вагомий аргумент: (1) "вихід" із середини - це, ймовірно, "гото", отже, природна відраза; (2) "вихід" у бібліотеки, безумовно, є поганою практикою (і все, що може стати бібліотекою), оскільки те, що бібліотека вважає "неповернутим", як правило, добре для абонента . (Примітка: використання винятків для виходів - це практична робота пітону для 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 відразу після виявлення можливої ​​корупції.

І після поступового sys.exit-ing з усіх циклів мені вдається це зробити.

Повний код: (деякі зміни були потрібні, оскільки це власний код для внутрішніх завдань):

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
Дякую за ваш внесок, але мені ця відповідь не має сенсу. Оскільки ви публікуєте лише кілька фрагментів коду замість повного прикладу, важко зрозуміти, що ви маєте на увазі. За винятком лише розміщених тут рядків коду сценарій вийшов би негайно. Я можу лише здогадуватися, що у вас є блок пробного захоплення, який ловить виняток SystemExit, який вже згадується в інших відповідях. Якщо ви перепишете свою відповідь з повним робочим прикладом того, як ви чисто виходите із програми (тобто виконуючи деякі необхідні дії щодо відключення), я думаю, що ваш пост може стати корисним доповненням.
wovano

Спасибі за ваш відгук. Тепер я додав ту частину коду, яка стосується заяв про вихід.
Матвій

Гаразд, це дає трохи більше контексту :) Хоча зараз я думаю, що ваше рішення насправді є вирішенням дуже поганих моделей програмування. Перш за все, ви ніколи не повинні використовувати except:без винятку тип. Якщо ви просто використовуєте except Exception:(або навіть більш детальний тип винятку, якщо це можливо), він sys.exit()буде працювати за призначенням, і вам не знадобиться ця обробка.
wovano

По-друге, схоже, що ви намагаєтесь виконати досить багато речей одним методом, або, мабуть, навіть у глобальній області файлів. Це допоможе розбити код на більш дрібні фрагменти (функції), наприклад: (1) завантажувати вхідний файл, (2) обробляти дані та (3) записувати вихідний файл. Тоді, якщо етап 1 не вдасться, ви пропустили б кроки 2 і 3. Ви можете підняти виняток у будь-якому місці під час кроку завантаження, і ви зможете обробити виняток в одному місці. Використання sys.exit()- це справді своєрідне рішення для критичних помилок. Всього два мої центи :)
wovano

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