Robienie czegoś przed zakończeniem programu


101

Jak możesz mieć funkcję lub coś, co zostanie wykonane przed zamknięciem programu? Mam skrypt, który będzie stale działał w tle i potrzebuję go do zapisania niektórych danych w pliku przed jego zamknięciem. Czy jest na to standardowy sposób?


2
Skrypt nie powinien nigdy się zatrzymywać, ale może ktoś zabije proces lub wciśnie Ctrl + \ lub coś.
RacecaR

Odpowiedzi:


165

Sprawdź atexitmoduł:

http://docs.python.org/library/atexit.html

Na przykład, jeśli chciałbym wydrukować komunikat, gdy moja aplikacja kończy działanie:

import atexit

def exit_handler():
    print 'My application is ending!'

atexit.register(exit_handler)

Należy tylko pamiętać, że działa to świetnie w przypadku normalnego zakończenia skryptu, ale nie zostanie wywołane we wszystkich przypadkach (np. Krytyczne błędy wewnętrzne).


5
Czy jest jakiś sposób, aby to zrobić tam, gdzie zostanie wywołane, jeśli naciśniesz Ctrl + C lub Ctrl + \?
RacecaR

8
Zostanie wywołany, jeśli naciśniesz Ctrl + C. To po prostu wywołuje wyjątek KeyboardInterrupt.
Ned Batchelder

1
Och, zapomniałem o tym. I zakładam, że nic, co możesz zrobić, nie zostanie uruchomione, jeśli ktoś zabije proces Pythona, prawda?
RacecaR

5
@RacecaR: rzeczywiście; celem zabicia procesu jest zatrzymanie go martwego. Od docs: Note The exit function is not called when the program is killed by a signal, when a Python fatal internal error is detected, or when os._exit() is called.
Katriel

18
@RacecaR, jedynym sposobem na uruchomienie kodu kończącego, nawet jeśli proces ulegnie poważnej awarii lub zostanie brutalnie zabity, jest inny proces, znany jako „monitor” lub „strażnik”, którego jedynym zadaniem jest obserwowanie procesu docelowego i uruchomić kod zakończenia, gdy jest to stosowne. Oczywiście wymaga to zupełnie innej architektury i ma swoje ograniczenia; jeśli potrzebujesz takiej funkcjonalności, najlepiej jest otworzyć inne pytanie w tej sprawie.
Alex Martelli

32

Jeśli chcesz, aby coś działało zawsze, nawet w przypadku błędów, użyj try: finally:tego -

def main():
    try:
        execute_app()
    finally:
        handle_cleanup()

if __name__=='__main__':
    main()

Jeśli chcesz również obsługiwać wyjątki, możesz wstawić except:przedfinally:


14
Nie działa, gdy pojawia się SIGTERM z powodu zabicia procesu.
ramu

16

Jeśli zatrzymasz skrypt, podnosząc znak KeyboardInterrupt(np. Naciskając Ctrl-C), możesz to złapać jako standardowy wyjątek. Możesz też złapać SystemExitw ten sam sposób.

try:
    ...
except KeyboardInterrupt:
    # clean up
    raise

Wspominam o tym, żebyście o tym wiedzieli; „właściwym” sposobem jest atexitwspomniany powyżej moduł.

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.