Jak zakończyć skrypt w języku Python


1075

Jestem świadomy die()polecenia w PHP, które wcześnie wychodzi ze skryptu.

Jak mogę to zrobić w Pythonie?

Odpowiedzi:


1414
import sys
sys.exit()

szczegóły z sysdokumentacji modułu :

sys.exit([arg])

Wyjdź z Pythona. Jest to realizowane przez podniesienie SystemExitwyjątku, więc działania czyszczące określone w klauzulach tryinstrukcji wreszcie są honorowane i możliwe jest przechwycenie próby wyjścia na poziomie zewnętrznym.

Opcjonalnym argumentem arg może być liczba całkowita podająca status wyjścia (domyślnie zero) lub inny typ obiektu. Jeśli jest liczbą całkowitą, zero jest uważane za „pomyślne zakończenie”, a każda niezerowa wartość jest uważana za „nienormalne zakończenie” przez powłoki i tym podobne. Większość systemów wymaga, aby znajdowała się w przedziale 0–127, aw przeciwnym razie daje niezdefiniowane wyniki. Niektóre systemy mają konwencję nadawania określonych znaczeń określonym kodom wyjścia, ale są one na ogół słabo rozwinięte; Programy uniksowe zwykle używają 2 dla błędów składni wiersza poleceń i 1 dla wszystkich innych rodzajów błędów. Jeśli przekazany zostanie inny typ obiektu, Żaden nie jest równoważny przekazaniu zera, a każdy inny obiekt jest drukowany do stderri powoduje kod wyjścia 1. W szczególności, sys.exit("some error message") to szybki sposób na zamknięcie programu w przypadku wystąpienia błędu.

Ponieważ exit()ostatecznie „tylko” wywołuje wyjątek, proces zostanie zakończony dopiero po wywołaniu z głównego wątku, a wyjątek nie zostanie przechwycony.

Pamiętaj, że jest to „miły” sposób na wyjście. @ glyphtwistedmatrix poniżej wskazuje, że jeśli chcesz „twardego wyjścia”, możesz go użyć os._exit(*errorcode*), chociaż prawdopodobnie jest on do pewnego stopnia specyficzny dla systemu operacyjnego (na przykład może nie brać kodu błędu w systemie Windows) i zdecydowanie jest mniej przyjazny, ponieważ jest nie pozwala tłumaczowi wykonać żadnego czyszczenia przed śmiercią procesu.


9
Prawdopodobnie sys.exit()nie działa (nie zabija procesu, po prostu zabija wątek), jeśli zostanie podniesiony przez wątek w tle?

@ cesium62: Tak, sys.exit()podnosi SystemExitwyjątek w bieżącym wątku.
Dmitry Trofimov

13
Czy istnieje sposób na zakończenie skryptu bez zgłaszania wyjątku? Już przekazuję odpowiednie flagi ze skryptu z wypisywaniem na standardowe potokowanie do Popena, więc wyjątek w tym przypadku powoduje więcej kłopotów niż rozwiązywania.
Elliot

4
Dlaczego, kiedy używam tej metody, otrzymuję następujące ostrzeżenie:UserWarning: To exit: use 'exit', 'quit', or Ctrl-D. warn("To exit: use 'exit', 'quit', or Ctrl-D.", stacklevel=1)
Bill

1
Potrzebujesz więcej szczegółów; może to zasługuje na własne pytanie?
pjz

349

Prostym sposobem wcześniejszego zakończenia skryptu Python jest użycie wbudowanej quit()funkcji. Nie ma potrzeby importowania żadnej biblioteki, a jest to wydajne i proste.

Przykład:

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

86
również sys.exit () zakończy wszystkie skrypty Pythona, ale quit () tylko zakończy skrypt, który go zrodził.
VishalDevgire,

4
Czy wiesz, czy to polecenie działa inaczej w Pythonie 2 i Pythonie 3?
David C.

1
Czy ktoś wie, czy spowoduje to zamknięcie całego interpretera, czy po prostu spowoduje, że skrypt przestanie działać? Mówiąc konkretnie: w przypadku skryptu działającego w Spyder interpreter Pythona pozostaje interaktywny, czy zostanie zabity? Spróbuj po prostu zatrzymać kontynuowanie skryptu, ale pozostaw interaktywność interpretera obecną.
Demis

3
dla mnie mówi się, że „wyjdź” nie jest zdefiniowane. Używam Pythona 3.
Vincenzooo

4
Jestem w Pythonie 3.7 i quit () zatrzymuje interpreter i zamyka skrypt.
RockAndRoleCoder

120

Innym sposobem jest:

raise SystemExit

36
@Alessa: wygląda bardziej elegancko, ale nie jest zalecane: bezpośrednio sys.exit
zgłaszasz

1
Jest to dla mnie idealny sposób: po prostu wyjdź z działającego skryptu, ale nie
wychodź


67

Chociaż ogólnie powinieneś preferować, sys.exitponieważ jest on bardziej „przyjazny” dla innego kodu, wszystko, co faktycznie robi, to podniesienie wyjątku.

Jeśli masz pewność, że musisz natychmiast wyjść z procesu i być może znajdujesz się w jakimś module obsługi wyjątków, który może się wyłapać SystemExit, istnieje inna funkcja - os._exit- która kończy się natychmiast na poziomie C i nie wykonuje żadnego normalnego usuwania tłumacza; na przykład haki zarejestrowane w module „atexit” nie są wykonywane.


43

Właśnie dowiedziałem się, że podczas pisania multithreadded aplikację, raise SystemExita sys.exit()zarówno zabija tylko wątkiem. Z drugiej strony os._exit()wychodzi z całego procesu. Zostało to omówione w „ Dlaczego sys.exit () nie kończy działania po wywołaniu wewnątrz wątku w Pythonie? ”.

Poniższy przykład ma 2 wątki. Kenny and Cartman. Cartman ma żyć wiecznie, ale Kenny jest nazywany rekurencyjnie i powinien umrzeć po 3 sekundach. (dzwonienie rekurencyjne nie jest najlepszym sposobem, ale miałem inne powody)

Jeśli chcemy również, aby Cartman umarł, gdy Kenny umiera, Kenny powinien odejść os._exit, w przeciwnym razie tylko Kenny umrze, a Cartman będzie żył wiecznie.

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
Wydaje się, że jest to jedyny sposób radzenia sobie z odrażająco odroczonymi wywołaniami zwrotnymi! (tj. metody wielowątkowe.)
not2qubit

1
Dobra robota. Żadna z pozostałych odpowiedzi nie odnosi się bezpośrednio do wielu wątków, tylko skrypty spawnujące inne skrypty.
anonimowy

33
from sys import exit
exit()

Jako parametr możesz przekazać kod wyjścia, który zostanie zwrócony do systemu operacyjnego. Domyślnie 0.


3
w moim przypadku nie musiałem nawet importować wyjścia.
Kostanos

5
Tylko dla potomności powyższego komentarza - exit()i sys.exit()to nie to samo. Nie używaj wbudowanych exit()skryptów, jest to tylko pomocnik dla interaktywnej powłoki - użyjsys.exit()
daveruinseverything

18

Jestem całkowitym nowicjuszem, ale na pewno jest to czystsze i bardziej kontrolowane

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

if __name__ == '__main__': 
    main()

...

Program zakończony

niż

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()

...

Program zakończony Traceback (ostatnie ostatnie wywołanie): Plik „Z: \ Directory \ testdieprogram.py”, wiersz 12, w main () Plik „Z: \ Directory \ testdieprogram.py”, wiersz 8, w głównym sys.exit ( ) SystemExit

Edytować

Chodzi o to, że program kończy się płynnie i spokojnie, zamiast „ZATRZYMAŁEM SIĘ !!!!”


19
Jednym z problemów może być, jeśli jesteś w zagnieżdżonych funkcjach i po prostu chcesz wyjść, albo musisz wysłać flagę z powrotem do górnej funkcji, albo po prostu wrócisz na wyższy poziom.
horta

11
Jest to absolutny nonsens, jeśli próbujesz zasugerować, że możesz użyć returndo zakończenia skryptu. Wszystko, co returnrobi, to zwrócenie wartości i przepływ kontroli do funkcji wywołującej. Tam kontynuuje wykonywanie zaraz po wywołaniu funkcji, która wywołała return. Oczywiście, jeśli returnjest to ostatnia instrukcja w twoim skrypcie, tak jak w twoim przykładzie, skrypt jest kończony zaraz po jego wywołaniu.
David Ferenczy Rogožan

1
Za takim podejściem można argumentować silnie: (1) „wyjście” ze środka jest prawdopodobnie „goto”, stąd naturalna awersja; (2) „wyjście” w bibliotekach jest zdecydowanie złą praktyką (i wszystko może stać się biblioteką), ponieważ to, co biblioteka uważa za „nie do odzyskania”, jest zazwyczaj w porządku dla osoby dzwoniącej . (Uwaga: stosowanie wyjątków przy wychodzeniu jest praktycznym obejściem dla Pythona dla programistów C / C ++ / Java zawsze niepoprawnie wywołujących exit- stąd programiści pythonowi mogą nie zauważyć smrodu tego kodu); i wreszcie (3) wielowątkowy kod (który pythoniści historycznie po prostu ignorowali).
Michał

8

W Pythonie 3.5 próbowałem włączyć podobny kod bez użycia modułów (np. Sys, Biopy) innych niż wbudowane, aby zatrzymać skrypt i wydrukować komunikat o błędzie moim użytkownikom. Oto mój przykład:

## 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

Później stwierdziłam, że bardziej zwięzłe jest po prostu zgłoszenie błędu:

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

Całkowicie się zgadzam, że lepiej jest zgłosić wyjątek dla każdego błędu, który może obsłużyć aplikacja. Pytanie dotyczyło jednak sposobu zakończenia skryptu w języku Python, więc nie jest to (nowa) odpowiedź na pytanie.
wovano

-1

Moje dwa centy.

Python 3.8.1, Windows 10, 64-bit.

sys.exit() nie działa bezpośrednio dla mnie.

Mam kilka następnych pętli.

Najpierw deklaruję zmienną boolowską, którą nazywam immediateExit.

Tak więc na początku kodu programu piszę:

immediateExit = False

Następnie, zaczynając od najbardziej wewnętrznego (zagnieżdżonego) wyjątku pętli, piszę:

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

Następnie przechodzę do bezpośredniej kontynuacji zewnętrznej pętli i zanim cokolwiek zostanie wykonane przez kod, piszę:

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

W zależności od złożoności, czasami powyższe stwierdzenie należy powtórzyć również w wyjątkach, itp.

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

Niestandardowy komunikat służy również do mojego osobistego debugowania, ponieważ liczby są w tym samym celu - aby zobaczyć, gdzie skrypt naprawdę się kończy.

'CSV file corrupted 1.5.'

W moim szczególnym przypadku przetwarzam plik CSV, którego nie chcę, aby oprogramowanie dotykało, jeśli oprogramowanie wykryje, że jest uszkodzony. Dlatego dla mnie bardzo ważne jest, aby wyjść z całego skryptu Python natychmiast po wykryciu możliwego uszkodzenia.

I postępując zgodnie ze stopniowym sys.exinging ze wszystkich pętli, udaje mi się to zrobić.

Pełny kod: (konieczne były pewne zmiany, ponieważ jest to zastrzeżony kod do zadań wewnętrznych):

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
Dziękuję za Twój wkład, ale dla mnie ta odpowiedź nie ma sensu. Ponieważ publikujesz tylko kilka fragmentów kodu zamiast pełnego przykładu, trudno zrozumieć, co masz na myśli. Tylko z wierszami kodu, które tu umieściłeś, skrypt natychmiast się zakończy. Mogę tylko zgadywać, że masz blok try-catch, który wychwytuje wyjątek SystemExit, który jest już wspomniany w innych odpowiedziach. Jeśli przepiszesz swoją odpowiedź z pełnym działającym przykładem tego, jak w czysty sposób zamkniesz aplikację (tj. Wykonując niezbędne czynności zamykające), myślę, że twój post może być przydatnym dodatkiem.
wovano

Dziękujemy za twoją opinię. Teraz dodałem część kodu, która dotyczy instrukcji wyjścia.
Matthew

Dobra, to daje nieco więcej kontekstu :) Chociaż teraz myślę, że twoje rozwiązanie jest w rzeczywistości obejściem bardzo złych wzorców programistycznych. Przede wszystkim nigdy nie należy używać except:bez typu wyjątku. Jeśli po prostu użyjesz except Exception:(lub nawet bardziej szczegółowy typ wyjątku, jeśli to możliwe), sys.exit()będzie działać zgodnie z przeznaczeniem i nie będziesz potrzebować tego obejścia.
wovano

Po drugie, wygląda na to, że próbujesz zrobić wiele rzeczy za pomocą jednej metody, a może nawet w globalnym zakresie plików. Pomoże to rozbić kod na mniejsze części (funkcje), na przykład: (1) załaduj plik wejściowy, (2) dane procesowe i (3) zapisz plik wyjściowy. Następnie, jeśli krok 1 nie powiedzie się, pominiesz kroki 2 i 3. Możesz zgłosić wyjątek w dowolnym miejscu podczas ładowania i możesz obsłużyć wyjątek w jednym miejscu. Korzystanie sys.exit()jest naprawdę rodzajem ostatecznego rozwiązania krytycznych błędów. Tylko moje dwa centy :)
wovano

Ogólnie rzecz biorąc, nie widzę globalnej funkcjonalności wyjścia / zatrzymania w Pythonie i jestem zmuszony to zrobić w ten sposób. Plik CSV jest dla mnie naprawdę krytyczny, więc strzegę go wszelkimi możliwymi środkami, nawet jeśli środki mogą wyglądać brzydko. Czytam The Hichhicker's Guide to Python, aby poprawić swój styl.
Matthew
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.