En lisant en ligne, certains programmeurs utilisent sys.exit
, d’autres SystemExit
.
Désolé pour la question de base:
Exemple
ref = osgeo.ogr.Open(reference)
if ref is None:
raise SystemExit('Unable to open %s' % reference)
ou
ref = osgeo.ogr.Open(reference)
if ref is None:
print('Unable to open %s' % reference)
sys.exit(-1)
Aucune différence pratique, mais il existe une autre différence dans votre exemple de code - print
passe à la sortie standard, mais le texte de l'exception passe à l'erreur standard (ce qui est probablement ce que vous voulez).
sys.exit(s)
est simplement un raccourci pour raise SystemExit(s)
, comme décrit dans le document docstring de l'ancien; essayez help(sys.exit)
. Donc, au lieu de l’un de vos exemples de programmes, vous pouvez faire
sys.exit('Unable to open %s' % reference)
Il y a 3 fonctions de sortie, en plus d'élever SystemExit
.
Le sous-jacent est os._exit
, qui requiert un argument de 1 int et se termine immédiatement sans nettoyage. Il est peu probable que vous souhaitiez toucher à celui-ci, mais c'est là.
sys.exit
est défini dans sysmodule.c et exécute simplement PyErr_SetObject(PyExc_SystemExit, exit_code);
, ce qui revient en fait à relancer directement SystemExit
. Dans le détail, relancer SystemExit
est probablement plus rapide, puisque sys.exit
nécessite un opcall LOAD_ATTR
et CALL_FUNCTION
vs RAISE_VARARGS
. De plus, raise SystemExit
produit un code binaire légèrement plus petit (moins de 4 octets), (1 octet supplémentaire si vous utilisez from sys import exit
car sys.exit
ne renverra aucun, ce qui inclut un POP_TOP
supplémentaire).
La dernière fonction de sortie est définie dans site.py
et est associée à exit
ou quit
dans le REPL. Il s’agit en fait d’une instance de la classe Quitter
(elle peut donc avoir un __repr__
personnalisé, elle est donc probablement la plus lente en cours d’exécution. En outre, elle ferme sys.stdin
avant de générer SystemExit
, elle est donc recommandée uniquement dans REPL.
Pour ce qui est de la gestion de SystemExit
, le VM appelle finalement os._exit, mais avant cela, il effectue un nettoyage. Il exécute également atexit._run_exitfuncs()
, qui exécute tous les rappels enregistrés via le module atexit
. L'appel de os._exit
contourne directement l'étape atexit
.
Ma préférence personnelle est qu’au moins SystemExit
soit soulevé (ou mieux encore - une exception personnalisée plus significative et bien documentée) et ensuite capturé aussi près que possible de la fonction "principale", ce qui peut alors avoir une dernière chance de le considérer comme telle. une sortie valide ou non. Les bibliothèques/fonctions profondément intégrées qui ont sys.exit
sont tout simplement désagréables du point de vue de la conception. (En général, la sortie doit être "aussi haute que possible")
SystemExit
est une exception, ce qui signifie que votre programme a eu un comportement tel que vous souhaitez l'arrêter et générer une erreur. sys.exit
est la fonction que vous pouvez appeler pour quitter votre programme, en donnant éventuellement un code de retour au système.
EDIT: ils sont en effet la même chose, donc la seule différence est dans la logique derrière votre programme. Une exception est une sorte de comportement "indésirable", qu'un appel à une fonction soit, du point de vue du programmeur, davantage une action "standard".
D'après la documentation, sys.exit(s)
fait effectivement raise SystemExit(s)
, c'est donc à peu près la même chose.
Bien que de nombreuses réponses aient répondu à la différence, https://mail.python.org/pipermail/python-list/2016-April/707470.html fait valoir un point intéressant:
TL; DR: Il est préférable de simplement lever une exception "normale" et d'utiliser SystemExit
ou sys.exit
uniquement aux niveaux supérieurs d'un script.
Je suis sur Python 2.7 et Linux, j'ai un code simple besoin de suggestion si je Je pourrais remplacer sys.exit (1) par raise SystemExit.
== Code actuel ==
def main(): try: create_logdir() create_dataset() unittest.main() except Exception as e: logging.exception(e) sys.exit(EXIT_STATUS_ERROR) if __== '__main__': main()
== Code modifié ==
def main(): try: create_logdir() create_dataset() unittest.main() except Exception as e: logging.exception(e) raise SystemExit if __== '__main__': main()
Je suis personnellement contre les deux. Mon modèle préféré est comme ce:
def main(argv): try: ... except Exception as e: logging.exception(e) return 1 if __== '__main__': sys.exit(main(sys.argv))
Notez que main () est redevenu une fonction normale avec résultats.
En outre, la plupart d’entre nous éviteraient le «sauf exception» et laisseraient un sommet level except bulle: de cette façon, vous obtenez une trace de pile pour débogage. Je suis d'accord, il empêche l'enregistrement de l'exception et fait pour sortie de la console plus laid, mais je pense que c'est une victoire. Et si vous voulez voulez pour enregistrer l'exception il y a toujours ceci:
essayer: ... sauf Exception comme e: logging.exception (e) élever
réciter l'exception dans le journal tout en la laissant échapper normalement.
Le problème avec le modèle "sauf exception" est qu'il capture et cachechaque exception, et pas seulement le jeu restreint d'exceptions spécifiques que vous comprenez.
Enfin, il est mal vu de créer une classe d'exception nue. Dans python 3 Je crois que c'est en fait interdit, donc c'est non portable. en tous cas. Mais même en Python, il est préférable de fournir une exception exemple, pas la classe:
soulève SystemExit (1)
Toutes les fonctions du bloc try ont une exception bouillonnée à l'aide de la levée
Exemple pour create_logdir (), voici la définition de la fonction
def create_logdir ():
essayer: os.makedirs (LOG_DIR) sauf OSError en tant que e: sys.stderr.write ("Echec de la création du répertoire de journalisation ... Exit !!!") élever print "fichier journal:" + corrupt_log retourne True
def main (): essayer: create_logdir () sauf exception comme e: logging.exception (e) soulève SystemExit
(a) En cas d'échec de create_logdir (), l'erreur ci-dessous sera générée, à savoir cette amende ou dois-je améliorer ce code.
Échec de la création du répertoire de journal ... Sortie !!! ERREUR: root: [Errno 17] Fichier existe: '/ var/log/dummy'
Traceback (dernier appel passé): Fichier "corrupt_test.py", ligne 245, dans le fichier principal create_logdir () Fichier "corrupt_test.py", ligne 53, dans create_logdir os.makedirs (LOG_DIR) Fichier "/usr/local/lib/python2.7/os.py", ligne 157, dans makedirs OSError: [Errno 17] Le fichier existe: '/ var/log/dummy'
Je préfère l’approche par bulles, peut-être avec un journal ou un avertissement messages comme vous l'avez fait, par exemple:
logging.exception ("create_logdir a échoué: makedirs (% r):% s"% (LOG_DIR, e)) augmenter
(En outre, le message de journal n'enregistre pas davantage de contexte: le contexte est très utile Utile pour les problèmes de débogage.)
Pour de très petits scripts, sys.stderr.write est correct, mais en général, aucun vos fonctions qui se sont révélées être généralement utiles pourraient migrer dans une bibliothèque pour être réutilisé; considérez que stderr n'est pas toujours la place pour les messages; lire à la place pour le module de journalisation avec error () ou wanr () ou exception () selon le cas. Il y a plus possibilité de configurer l'emplacement de la sortie sans câblage cela dans vos fonctions intérieures.
Puis-je avoir juste soulever, au lieu de SystemExit ou sys.exit (1). Ce me semble faux
def main ():
essayer: create_logdir () sauf exception comme e logging.exception (e) élever
C'est ce que je ferais moi-même.
Pensez: l'exception a-t-elle été "gérée", c'est-à-dire que la situation est été traité parce que c'était prévu? Sinon, laissez l'exception dégager une bulle pour que l'utilisateur sache que quelque chose pas est compris par le programme a eu lieu.
Enfin, il est généralement mauvais pour SystemExit ou sys.exit () de l’intérieur autre chose que la fonction principale () la plus externe. Et je résiste même là; la fonction principale, si elle est bien écrite, peut souvent s'appeler utile ailleurs, ce qui en fait effectivement une bibliothèque fonction (il a été réutilisé). Une telle fonction ne devrait pas abandonner unilatéralement le programme. Si vulgaire! Au lieu de cela, laissez l'exception bubble out: peut-être que le caller de main () l'attend et peut gérer il. En abandonnant et non en "augmentant", vous avez privé l'appelant de la chance de faire quelque chose de approprié, même si vous-même (c'est-à-dire "main") ne connaissent pas assez de contexte pour gérer l'exception.
Donc, je suis pour "élever" moi-même. Et ensuite uniquement parce que vous souhaitez enregistrer le fichier Erreur. Si vous ne voulez pas vous connecter à l'exception, vous pouvez éviter le essayez/sauf entièrement et utilisez un code plus simple: laissez l’appelant s’inquiéter sur les exceptions non gérées!