Comment terminer un script Python

1079

Je connais la die()commande en PHP qui quitte un script tôt.

Comment puis-je faire cela en Python?

Teifion
la source

Réponses:

1418
import sys
sys.exit()

détails de la sysdocumentation du module :

sys.exit([arg])

Quittez Python. Ceci est implémenté en levant l' SystemExitexception, donc les actions de nettoyage spécifiées par les clauses finally des tryinstructions sont honorées, et il est possible d'intercepter la tentative de sortie à un niveau externe.

L'argument optionnel arg peut être un entier donnant le statut de sortie (par défaut à zéro), ou un autre type d'objet. S'il s'agit d'un entier, zéro est considéré comme une «terminaison réussie» et toute valeur non nulle est considérée comme une «terminaison anormale» par des coques et similaires. La plupart des systèmes exigent qu'il soit compris entre 0 et 127 et produisent autrement des résultats indéfinis. Certains systèmes ont une convention pour attribuer des significations spécifiques à des codes de sortie spécifiques, mais ceux-ci sont généralement sous-développés; Les programmes Unix utilisent généralement 2 pour les erreurs de syntaxe de ligne de commande et 1 pour tous les autres types d'erreurs. Si un autre type d'objet est transmis, Aucun équivaut à passer à zéro, et tout autre objet est imprimé stderret entraîne un code de sortie de 1. En particulier, sys.exit("some error message") est un moyen rapide de quitter un programme en cas d'erreur.

Puisqu'en exit()fin de compte «seulement» lève une exception, il ne quittera le processus que lorsqu'il sera appelé à partir du thread principal, et l'exception ne sera pas interceptée.

Notez que c'est la «belle» façon de quitter. @ glyphtwistedmatrix ci-dessous souligne que si vous voulez une `` sortie matérielle '', vous pouvez l'utiliser os._exit(*errorcode*), bien que ce soit probablement spécifique à l'OS dans une certaine mesure (cela pourrait ne pas prendre un code d'erreur sous Windows, par exemple), et c'est certainement moins convivial car il ne laisse pas l'interprète effectuer le nettoyage avant la fin du processus.

pjz
la source
9
Vraisemblablement sys.exit()ne fonctionne pas (ne tue pas le processus, tue simplement le fil) s'il est déclenché par un fil d'arrière-plan?
@ cesium62: Oui, sys.exit()déclenche une SystemExitexception dans le thread actuel.
Dmitry Trofimov
13
Existe-t-il un moyen de terminer un script sans déclencher une exception? Je passe déjà des drapeaux pertinents hors du script avec des canalisations print to stdout dans Popen, donc l'exception dans ce cas cause plus de problèmes qu'elle n'en résout.
Elliot
4
Pourquoi, lorsque j'utilise cette méthode, j'obtiens l'avertissement suivant:UserWarning: To exit: use 'exit', 'quit', or Ctrl-D. warn("To exit: use 'exit', 'quit', or Ctrl-D.", stacklevel=1)
Bill
1
Besoin de plus de détails; peut-être que cela mérite d'être sa propre question?
pjz
349

Un moyen simple de terminer un script Python tôt est d'utiliser la quit()fonction intégrée. Il n'est pas nécessaire d'importer de bibliothèque, et c'est efficace et simple.

Exemple:

#do stuff
if this == that:
  quit()
jmgr
la source
86
sys.exit () terminera également tous les scripts python, mais quit () ne terminera que le script qui l'a engendré.
VishalDevgire
4
Savez-vous si cette commande fonctionne différemment en python 2 et python 3?
David C.
1
Est-ce que quelqu'un sait si cela va quitter l'intégralité de l'interpréteur, ou simplement arrêter l'exécution du script? Plus précisément: pour un script exécuté dans Spyder, avec l'interpréteur Python rester interactif, ou sera-t-il tué? Essayez simplement d'arrêter le script, mais laissez l'interactivité de l'interpréteur présente.
Demis
3
pour moi, il dit que «quitter» n'est pas défini. J'utilise python 3.
Vincenzooo
4
Je suis en python 3.7 et quit () arrête l'interpréteur et ferme le script.
RockAndRoleCoder du
120

Une autre façon est:

raise SystemExit
Vhaerun
la source
36
@Alessa: il a l'air plus élégant, mais ce n'est pas recommandé: vous déclenchez directement une exception intégrée au lieu du sys.exitwrapper préférable (et
écrasable
1
C'est un moyen parfait pour moi: il suffit de quitter le script en cours d'exécution mais pas de quitter IDLE
rml
78

Vous pouvez également utiliser simplement exit().

Gardez à l' esprit que sys.exit(), exit(), quit()et os._exit(0) tuer l'interpréteur Python. Par conséquent, s'il apparaît dans un script appelé à partir d'un autre script par execfile(), il arrête l'exécution des deux scripts.

Voir " Arrêter l'exécution d'un script appelé avec execfile " pour éviter cela.

Cowboy de l'espace
la source
67

Bien que vous devriez généralement le préférer sys.exitcar il est plus "convivial" avec un autre code, il ne fait que lever une exception.

Si vous êtes sûr que vous devez quitter un processus immédiatement, et que vous pourriez être à l'intérieur d'un gestionnaire d'exception qui se bloquerait SystemExit, il existe une autre fonction - os._exit- qui se termine immédiatement au niveau C et n'effectue aucune des opérations normales de démontage. de l'interprète; par exemple, les hooks enregistrés avec le module "atexit" ne sont pas exécutés.

Glyphe
la source
43

Je viens de découvrir que lors de l'écriture d'une application multithread, raise SystemExitet les sys.exit()deux ne tuent que le thread en cours d'exécution. En revanche, os._exit()quitte tout le processus. Cela a été discuté dans " Pourquoi sys.exit () ne se ferme-t-il pas lorsqu'il est appelé dans un thread en Python? ".

L'exemple ci-dessous a 2 threads. Kenny et Cartman. Cartman est censé vivre pour toujours, mais Kenny est appelé récursivement et devrait mourir après 3 secondes. (les appels récursifs ne sont pas la meilleure façon, mais j'avais d'autres raisons)

Si nous voulons également que Cartman meure à la mort de Kenny, Kenny devrait s'en aller os._exit, sinon Kenny mourra et Cartman vivra pour toujours.

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()
eaydin
la source
1
Cela semble être la seule façon de gérer les rappels odieusement différés! (c.-à-d. méthodes multi-thread.)
not2qubit
1
Bien joué. Aucune des autres réponses ne concerne directement plusieurs threads, seuls les scripts engendrant d'autres scripts.
anonyme
33
from sys import exit
exit()

En tant que paramètre, vous pouvez transmettre un code de sortie, qui sera renvoyé à l'OS. La valeur par défaut est 0.

cleg
la source
3
dans mon cas, je n'avais même pas besoin d'importer la sortie.
Kostanos
5
Juste pour la postérité sur le commentaire ci-dessus - exit()et ce sys.exit()n'est pas la même chose. N'utilisez pas les exit()scripts intégrés , c'est juste une aide pour le shell interactif - utilisezsys.exit()
daveruinseverything
18

Je suis un novice total mais c'est sûrement plus propre et plus contrôlé

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

if __name__ == '__main__': 
    main()

...

Programme terminé

que

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

...

Programme terminé Traceback (dernier appel le plus récent): Fichier "Z: \ Directory \ testdieprogram.py", ligne 12, dans main () Fichier "Z: \ Directory \ testdieprogram.py", ligne 8, dans sys.exit principal ( ) SystemExit

Éditer

Le point étant que le programme se termine en douceur et en paix, plutôt que "J'AI ARRÊTÉ !!!!"

Floggedhorse
la source
20
Un problème serait que si vous êtes dans des fonctions imbriquées et que vous souhaitez simplement quitter, vous devez soit envoyer un indicateur tout en remontant à la fonction supérieure, soit revenir au niveau supérieur suivant.
horta
11
C'est un non-sens absolu si vous essayez de suggérer que vous pouvez utiliser returnpour terminer le script. Tout ce que returnfait est de renvoyer une valeur et un flux de contrôle à la fonction appelante. Là, il continue avec l'exécution juste après l'appel de la fonction qui a appelé return. Bien sûr, si le returnest la dernière instruction de votre script comme dans votre exemple, le script se termine juste après son appel.
David Ferenczy Rogožan
1
Il y a un argument solide à faire pour cette approche: (1) la "sortie" du milieu est sans doute un "goto", donc une aversion naturelle; (2) La «sortie» dans les bibliothèques est définitivement une mauvaise pratique (et tout peut devenir une bibliothèque), car ce qu'une bibliothèque considère comme «irrécupérable» convient généralement à l' appelant . (Remarque: l'utilisation d'exceptions pour les sorties est un contournement pratique de python pour les développeurs C / C ++ / Java appelant toujours de manière inappropriée exit- par conséquent, les programmeurs python peuvent ne pas remarquer autant l'odeur de ce code); et enfin, (3) du code multi-thread (que les pythonistes ont historiquement ignoré).
michael
8

Dans Python 3.5, j'ai essayé d'incorporer un code similaire sans utiliser de modules (par exemple sys, Biopy) autres que ceux intégrés pour arrêter le script et imprimer un message d'erreur à mes utilisateurs. Voici mon exemple:

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

Plus tard, j'ai trouvé qu'il était plus succinct de simplement lancer une erreur:

## My example revised:
if "ATG" in my_DNA: 
    ## <Do something & proceed...>
else: 
    raise ValueError("Start codon is missing! Check your DNA sequence!")
David C.
la source
Je suis entièrement d'accord qu'il est préférable de lever une exception pour toute erreur pouvant être gérée par l'application. Mais la question était de savoir comment terminer un script Python, donc ce n'est pas vraiment une (nouvelle) réponse à la question.
wovano
-1

Mes deux centimes.

Python 3.8.1, Windows 10, 64 bits.

sys.exit() ne fonctionne pas directement pour moi.

J'ai plusieurs boucles suivantes.

Je déclare d'abord une variable booléenne, que j'appelle immediateExit.

Donc, au début du code du programme, j'écris:

immediateExit = False

Ensuite, à partir de l'exception de boucle la plus interne (imbriquée), j'écris:

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

Ensuite, j'entre dans la suite immédiate de la boucle externe, et avant toute autre chose exécutée par le code, j'écris:

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

Selon la complexité, la déclaration ci-dessus doit parfois être répétée également dans les sections sauf, etc.

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

Le message personnalisé est également destiné à mon débogage personnel, car les chiffres sont dans le même but - pour voir où le script se termine réellement.

'CSV file corrupted 1.5.'

Dans mon cas particulier, je traite un fichier CSV, auquel je ne veux pas que le logiciel touche, si le logiciel détecte qu'il est corrompu. Par conséquent, pour moi, il est très important de quitter l'intégralité du script Python immédiatement après avoir détecté la corruption possible.

Et en suivant la sortie progressive de toutes les boucles, j'arrive à le faire.

Code complet: (certaines modifications étaient nécessaires car il s'agit d'un code propriétaire pour les tâches internes):

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.')
Matthieu
la source
1
Merci pour votre contribution, mais pour moi cette réponse n'a aucun sens. Comme vous ne publiez que quelques extraits de code au lieu d'un exemple complet, il est difficile de comprendre ce que vous voulez dire. Avec seulement les lignes de code que vous avez publiées ici, le script se fermerait immédiatement. Je peux seulement deviner que vous avez un bloc try-catch, qui intercepte l'exception SystemExit qui est déjà mentionnée dans d'autres réponses. Si vous voulez réécrire votre réponse avec un exemple complet de la façon dont vous quitteriez proprement une application (c'est-à-dire en effectuant certaines actions d'arrêt nécessaires), je pense que votre message pourrait être un ajout utile.
wovano
Merci pour votre avis. Maintenant, j'ai ajouté la partie du code, qui concerne les instructions de sortie.
Matthew
D'accord, cela donne un peu plus de contexte :) Bien que maintenant je pense que votre solution est en fait une solution de contournement pour de très mauvais schémas de programmation. Tout d'abord, vous ne devez jamais utiliser except:sans type d'exception. Si vous utilisez simplement except Exception:(ou même un type d'exception plus détaillé si possible), le sys.exit()fonctionnerait comme prévu et vous n'auriez pas besoin de cette solution de contournement.
wovano
Deuxièmement, il semble que vous essayez de faire un certain nombre de choses dans une même méthode, ou probablement même dans la portée du fichier global. Cela aiderait à décomposer votre code en petits morceaux (fonctions), par exemple: (1) charger le fichier d'entrée, (2) traiter les données et (3) écrire le fichier de sortie. Ensuite, si l'étape 1 échouait, vous sauteriez les étapes 2 et 3. Vous pouvez déclencher une exception n'importe où pendant l'étape de chargement et vous pouvez gérer l'exception à un seul endroit. L'utilisation sys.exit()est en réalité une sorte de solution de dernier recours pour les erreurs critiques. Juste mes deux cents :)
wovano
En général, je ne vois pas de fonctionnalité globale de sortie / arrêt en Python, et je suis obligé de le faire de cette façon. Le fichier CSV est vraiment critique pour moi, donc je le garde par tous les moyens possibles, même si le moyen peut sembler laid. Je lis le Guide de Hichhicker sur Python pour améliorer mon style.
Matthew