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.
J'essaierai plusieurs méthodes. Pour ceux qui sont pressés, j'écrirai d'abord la conclusion.
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())
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())
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.
essayez - enfin
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.
dans atexit
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.
Alors, essayez - enfin ou atexit et le signal doit être combiné.
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.
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.
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