Je veux faire quelque chose avec Python à la fin

Je veux faire quelque chose avec Python à la fin

Je crée un répertoire en cours de route, mais je ne veux pas qu'il reste à la fin. J'ai mis des données temporaires dans la base de données, mais je ne veux pas qu'elles restent à la fin. Veuillez me faire savoir quand le programme est terminé, s'il est normal ou mort.

C'est une façon d'y parvenir.

Cette fois, je viserai les choses suivantes.

  1. Bien sûr, je veux que vous le fassiez si c'est normal
  2. Je veux que vous exécutiez même si une exception se produit
  3. Je veux que vous exécutiez même si vous vous arrêtez avec Ctrl-C
  4. Je veux que vous exécutiez même si vous arrêtez de tuer
  5. Ne vous arrêtez pas pendant le processus de nettoyage
  6. Abandonnez kill -9 et Segmentaion Fault

J'essaierai plusieurs méthodes. Pour ceux qui sont pressés, j'écrirai d'abord la conclusion.

Conclusion d'abord

import sys
import time
import signal


def setup():
    print("!!!Set up!!!")


def cleanup():
    print("!!!Clean up!!!")
    #Traitement de nettoyage divers
    time.sleep(10)
    print("!!!Clean up Done!!!")


def sig_handler(signum, frame) -> None:
    sys.exit(1)


def main():
    setup()
    signal.signal(signal.SIGTERM, sig_handler)
    try:
        #Traitement divers
        time.sleep(60)

    finally:
        signal.signal(signal.SIGTERM, signal.SIG_IGN)
        signal.signal(signal.SIGINT, signal.SIG_IGN)
        cleanup()
        signal.signal(signal.SIGTERM, signal.SIG_DFL)
        signal.signal(signal.SIGINT, signal.SIG_DFL)


if __name__ == "__main__":
    sys.exit(main())

Commentaire

Préparation

Préparez la fonction setup () / clean () et la partie principale.

def setup():
    print("!!!Set up!!!")


def cleanup():
    print("!!!Clean up!!!")

def main():
    pass

if __name__ == "__main__":
    sys.exit(main())

utiliser try --finally

La première chose qui me vient à l'esprit est d'utiliser try - enfin.

def main():
    setup()
    try:
        print("Do some jobs")

    finally:
        cleanup()

Lançons-le.

!!!set up!!!
do some jobs
!!!Clean up!!!

Il a été nettoyé. Mais que faire si une erreur survient en cours de route?

def main():
    setup()
    try:
        print(1 / 0)

    finally:
        cleanup()

Je vais essayer.

!!!set up!!!
!!!Clean up!!!
Traceback (most recent call last):
  File "./try-finally.py", line 26, in <module>
    sys.exit(main())
  File "./try-finally.py", line 19, in main
    print(1 / 0)
ZeroDivisionError: division by zero

Cela a également été nettoyé.

Mais que faire si vous vous arrêtez avec Ctrl-C?

def main():
    setup()
    try:
        time.sleep(60)

    finally:
        cleanup()

Exécutez-le et appuyez sur Ctrl-C au milieu pour l'arrêter.

!!!Set up!!!
^C!!!Clean up!!!
Traceback (most recent call last):
  File "./try-finally.py", line 27, in <module>
    sys.exit(main())
  File "./try-finally.py", line 20, in main
    time.sleep(60)
KeyboardInterrupt

Apparemment, cela a fonctionné.

Mais que faire si vous tuiez avec kill?

!!!Set up!!!
Terminated

Cela ne devrait pas être fait. Cela laissera un fichier poubelle.

Conclusion

essayez - enfin

  1. Bien sûr, je veux que vous le fassiez si c'est normal ⇨ ○
  2. Je veux que vous exécutiez même si une exception se produit ⇨ ○
  3. Je veux que vous exécutiez même si vous vous arrêtez avec Ctrl-C ⇨ ○
  4. Je veux que vous exécutiez même si vous arrêtez avec kill ⇨ ×

utiliser atexit

Python a un atexit qui l'exécutera à la sortie. Essayons ça.

def main():
    setup()
    atexit.register(cleanup)

    print("Do some jobs")

Lançons-le.

!!!Set up!!!
Do some jobs
!!!Clean up!!!

Ça s'est bien passé. Ensuite, obtenons une erreur.

def main():
    setup()
    atexit.register(cleanup)

    print(1 / 0)

Je vais essayer.

!!!Set up!!!
Traceback (most recent call last):
  File "./try-finally.py", line 25, in <module>
    sys.exit(main())
  File "./try-finally.py", line 21, in main
    print(1 / 0)
ZeroDivisionError: division by zero
!!!Clean up!!!

Cela a également fonctionné. Par rapport au cas de try --finalement, le processus de nettoyage est plus tardif.

Et si vous vous arrêtez avec Ctrl-C?

def main():
    setup()
    atexit.register(cleanup)

    time.sleep(60)

Exécutez-le et essayez de l'arrêter avec Ctrl-C au milieu.

!!!Set up!!!
^CTraceback (most recent call last):
  File "./try-finally.py", line 25, in <module>
    sys.exit(main())
  File "./try-finally.py", line 21, in main
    time.sleep(60)
KeyboardInterrupt
!!!Clean up!!!

se sentir bien.

Puis, enfin, arrêtons avec tuer.

!!!Set up!!!
Terminated

Pardon. Comme essayez-enfin, cela ne semble pas fonctionner non plus.

Conclusion

dans atexit

  1. Bien sûr, je veux que vous le fassiez si c'est normal ⇨ ○
  2. Je veux que vous exécutiez même si une exception se produit ⇨ ○
  3. Je veux que vous exécutiez même si vous vous arrêtez avec Ctrl-C ⇨ ○
  4. Je veux que vous exécutiez même si vous arrêtez avec kill ⇨ ×

utiliser le signal

La commande kill envoie un signal appelé SIGTERM au processus. Ctrl-C envoie également un signal appelé SIGINT au processus. Essayons de piéger ces signaux.

def sig_handler(signum, frame) -> None:
    cleanup()
    sys.exit(1)


def main():
    setup()
    signal.signal(signal.SIGTERM, sig_handler)
    signal.signal(signal.SIGINT, sig_handler)

    print("Do some jobs")

Je vais essayer.

!!!Set up!!!
Do some jobs

Le nettoyage ne sera pas effectué. C'est parce que le signal n'a pas volé de l'extérieur. C'est naturel. Puisque l'exception est la même, la confirmation est omise.

Voyons maintenant ce qui se passe avec Ctrl-C.

def main():
    setup()
    signal.signal(signal.SIGTERM, sig_handler)
    signal.signal(signal.SIGINT, sig_handler)

    time.sleep(60)

Exécutez-le et essayez de l'arrêter avec Ctrl-C au milieu.

!!!Set up!!!
^C!!!Clean up!!!

C'est parfait. L'exception KeyboardInterrupt a disparu, mais cela ne devrait généralement pas poser de problème. Si c'est absolument nécessaire, vous pouvez augmenter (KeyboardInterrupt ()) dans sig_handler.

Ensuite, c'est une tuerie dont il faut s'inquiéter, mais que va-t-il se passer?

!!!Set up!!!
!!!Clean up!!!

Génial! Il a été nettoyé avec un kitin.

Conclusion

  1. Bien sûr, je veux que vous l'exécutiez si c'est normal ⇨ ×
  2. Je veux que vous exécutiez même si une exception se produit ⇨ ×
  3. Je veux que vous exécutiez même si vous vous arrêtez avec Ctrl-C ⇨ ○
  4. Je veux que vous exécutiez même si vous arrêtez avec kill ⇨ ○

Alors, essayez - enfin ou atexit et le signal doit être combiné.

utiliser try - enfin en combinaison avec le signal

Cette fois, en supposant que la portée est étroite, je vais essayer de combiner essai - enfin et signal.

def sig_handler(signum, frame) -> None:
    cleanup()
    sys.exit(1)


def main():
    setup()
    signal.signal(signal.SIGTERM, sig_handler)
    try:
        print("do some jobs")

    finally:
        signal.signal(signal.SIGTERM, signal.SIG_DFL)
        cleanup()

C'est devenu comme ça. Ctrl-C fonctionne également avec try --finally, donc je n'ai piégé que SIGTERM. Après avoir quitté l'essai, le nettoyage ne devrait pas être nécessaire, alors définissez finalement SIGTERM sur la valeur par défaut.

Lançons-le.

!!!Set up!!!
do some jobs
!!!Clean up!!!

Comme prévu.

Ensuite, obtenons une erreur.

def main():
    setup()
    signal.signal(signal.SIGTERM, sig_handler)
    try:
        print(1 / 0)

    finally:
        signal.signal(signal.SIGTERM, signal.SIG_DFL)
        cleanup()


if __name__ == "__main__":
    sys.exit(main())

Je vais essayer.

!!!Set up!!!
!!!Clean up!!!
Traceback (most recent call last):
  File "./try-finally.py", line 33, in <module>
    sys.exit(main())
  File "./try-finally.py", line 26, in main
    print(1 / 0)
ZeroDivisionError: division by zero

Il a été nettoyé.

Ensuite, vérifiez Ctrl-C.

def main():
    setup()
    signal.signal(signal.SIGTERM, sig_handler)
    try:
        time.sleep(60)

    finally:
        signal.signal(signal.SIGTERM, signal.SIG_DFL)
        cleanup()

Exécutez-le et essayez d'appuyer sur Ctrl-C au milieu.

!!!Set up!!!
^CClean up!!
Traceback (most recent call last):
  File "./try-finally.py", line 33, in <module>
    sys.exit(main())
  File "./try-finally.py", line 26, in main
    time.sleep(60)
KeyboardInterrupt

Cela a également été nettoyé.

Maintenant, qu'en est-il de tuer?

!!!Set up!!!
!!!Clean up!!!
!!!Clean up!!!

hein! Il a été nettoyé deux fois.

En piégeant SIGTERM, il semble que Python n'ait pas tué et exécuté finalement. Alors, changeons sig_handler comme suit.

def sig_handler(signum, frame) -> None:
    sys.exit(1)

J'ai arrêté d'appeler le nettoyage dans le gestionnaire et je l'ai juste terminé.

Exécutez-le et essayez de le tuer.

!!!Set up!!!
!!!Clean up!!!

C'est finalement comme prévu.

Conclusion

  1. Bien sûr, je veux que vous le fassiez si c'est normal ⇨ ○
  2. Je veux que vous exécutiez même si une exception se produit ⇨ ○
  3. Je veux que vous exécutiez même si vous vous arrêtez avec Ctrl-C ⇨ ○
  4. Je veux que vous exécutiez même si vous arrêtez avec kill ⇨ ○

Ne vous arrêtez pas pendant le processus de nettoyage

La méthode précédente est suffisante, mais il est dans la nature humaine d'appuyer sur Ctrl-C à plusieurs reprises si vous ne vous arrêtez pas immédiatement après avoir appuyé sur Ctrl-C. Vous pouvez également exécuter kill plusieurs fois.

J'ai fait fonctionner le processus de nettoyage, mais c'est un gâchis. Donc, je ne l'arrêterai pas pendant le nettoyage.

def main():
    setup()
    signal.signal(signal.SIGTERM, sig_handler)
    try:
        time.sleep(60)

    finally:
        signal.signal(signal.SIGTERM, signal.SIG_IGN)
        signal.signal(signal.SIGINT, signal.SIG_IGN)
        cleanup()
        signal.signal(signal.SIGTERM, signal.SIG_DFL)
        signal.signal(signal.SIGINT, signal.SIG_DFL)

Ignorez Ctrl-C et tuez les signaux avant le nettoyage (). Après cleanup (), restaurez la valeur par défaut. C'est parfait.

Conclusion

  1. Bien sûr, je veux que vous le fassiez si c'est normal ⇨ ○
  2. Je veux que vous exécutiez même si une exception se produit ⇨ ○
  3. Je veux que vous exécutiez même si vous vous arrêtez avec Ctrl-C ⇨ ○
  4. Je veux que vous exécutiez même si vous arrêtez avec kill ⇨ ○
  5. Ne vous arrêtez pas au milieu du processus de résiliation ⇨ ○

prime

Utilisez try --finally / atexit correctement

En regardant les résultats cette fois, il semble que la seule différence entre try-catch et atexit soit la différence de portée et de timing. Si l'installation s'exécute au milieu d'un programme, utilisez try --finally dans cette étendue. Si l'installation est la première chose que vous exécutez dans votre programme, utilisez atexit. Si vous souhaitez qu'il s'exécute à tout moment à la fin, quelle que soit la configuration, utilisez atexit. Cela signifie t-il?

En outre, il existe un moyen d'utiliser avec, donc si vous êtes intéressé, essayez-le.

Recommended Posts

Je veux faire quelque chose avec Python à la fin
Je veux faire quelque chose comme sort uniq en Python
Je voulais faire quelque chose comme la pipe d'Elixir en Python
Je veux créer une fenêtre avec Python
Je veux fusionner des dictionnaires imbriqués en Python
Je veux afficher la progression en Python!
Je veux faire un patch monkey seulement en partie en toute sécurité avec Python
Je veux écrire en Python! (1) Vérification du format de code
Je souhaite intégrer une variable dans une chaîne Python
Je veux facilement implémenter le délai d'expiration en python
Je veux écrire en Python! (2) Écrivons un test
Même avec JavaScript, je veux voir Python `range ()`!
Je veux échantillonner au hasard un fichier avec Python
Je veux travailler avec un robot en python.
Je veux écrire en Python! (3) Utiliser des simulacres
Je veux manipuler des chaînes dans Kotlin comme Python!
Je veux améliorer l'efficacité avec Python même dans un système expérimental (3) Je veux faire quelque chose comme Excel avec Pandas
[Python] Comment faire PCA avec Python
Je veux faire ○○ avec les Pandas
Je veux déboguer avec Python
Que faire lorsque "SSL: CERTIFICATE_VERIFY_FAILED _ssl.c: 1056" apparaît en Python
Je veux ajouter un joli complément à input () en python
[Sous-processus] Lorsque vous souhaitez exécuter un autre programme Python en code Python
J'ai essayé d'implémenter la permutation en Python
Je veux imprimer dans la notation d'inclusion
Comment faire R chartr () en Python
Je veux résoudre APG4b avec Python (seulement 4.01 et 4.04 au chapitre 4)
J'ai essayé d'implémenter PLSA dans Python 2
Je veux créer un environnement Python
Je veux exécuter l'interface graphique Python au démarrage de Raspberry Pi
Je souhaite rechercher le texte intégral avec elasticsearch + python
[Python] Lorsque vous souhaitez utiliser toutes les variables dans un autre fichier
Je veux analyser les journaux avec Python
Je veux jouer avec aws avec python
[Couches Python / AWS Lambda] Je souhaite réutiliser uniquement le module dans AWS Lambda Layers
J'ai essayé d'implémenter ADALINE en Python
Je voulais résoudre ABC159 avec Python
Je veux intégrer Matplotlib dans PySimpleGUI
Que faire lorsque ModuleNotFoundError: Aucun module nommé'XXX 'ne se produit en Python
Une histoire que je voulais faire quand j'ai eu une liste de sessions d'étude avec Python
Que faire lorsque le type de valeur est ambigu en Python?
Je veux le faire avec Python lambda Django, mais je vais m'arrêter
Je souhaite convertir une table convertie en PDF en Python en CSV
Je veux convertir par lots le résultat de "chaîne de caractères" .split () en Python
Je veux expliquer en détail la classe abstraite (ABCmeta) de Python
Je veux colorer une partie de la chaîne Excel avec Python
Après tout, que dois-je utiliser pour faire des comparaisons de types en Python?
Je veux utiliser MATLAB feval avec python
Je veux corriger Datetime.now dans le test de Django
Je veux mémoriser, y compris les arguments de mots clés de Python
[Python] Ce que j'ai fait pour faire un test unitaire
Python: j'ai pu récurer en lambda
Je souhaite envoyer un e-mail depuis Gmail en utilisant Python.
Quand j'essaye matplotlib en Python, il dit 'cairo.Context'
[Python] Je veux gérer 7DaysToDie depuis Discord! 1/3
Implémentation minimale d'Union Find en Python
Je veux faire un jeu avec Python
J'ai écrit "Introduction à la vérification des effets" en Python
Je souhaite stocker les informations de la base de données dans la liste