Saya sedang mengerjakan skrip python yang memulai beberapa proses dan koneksi basis data. Sesekali saya ingin membunuh skrip dengan aCtrlC sinyal + , dan saya ingin melakukan pembersihan.
Di Perl saya akan melakukan ini:
$SIG{'INT'} = 'exit_gracefully';
sub exit_gracefully {
print "Caught ^C \n";
exit (0);
}
Bagaimana saya melakukan analog ini dengan Python?
./program.py > output.log
,. Ketika Anda menekan Ctrl-C, Anda ingin program Anda keluar dengan anggun dengan membuatnya mencatat bahwa semua file data telah dihapus dan ditandai bersih untuk mengonfirmasi bahwa semuanya dibiarkan dalam kondisi baik yang diketahui. Tetapi Ctrl-C mengirimkan SIGINT ke semua proses dalam satu pipeline, sehingga shell dapat menutup STDOUT (sekarang "output.log") sebelum program.py selesai mencetak log terakhir. Python akan mengeluh, "tutup gagal pada penghancur objek file: Kesalahan di sys.excepthook:".Anda dapat memperlakukannya seperti pengecualian (KeyboardInterrupt), seperti yang lainnya. Buat file baru dan jalankan dari shell Anda dengan konten berikut untuk melihat apa yang saya maksud:
sumber
signal.signal(signal.SIGINT, signal.default_int_handler)
atau Anda akan gagal, karena KeyboardInterrupt tidak memecat dalam setiap situasi di mana ia harus memecat! Detailnya ada di sini .Dan sebagai manajer konteks:
Menggunakan:
Penangan bersarang:
Dari sini: https://gist.github.com/2907502
sumber
StopIteration
untuk mematahkan loop terdalam ketika ctrl-C ditekan, kan?Anda dapat menangani CTRL+ Cdengan menangkap
KeyboardInterrupt
pengecualian. Anda bisa menerapkan kode pembersihan apa pun di penangan pengecualian.sumber
Dari dokumentasi Python :
sumber
Cuplikan Lain
Disebut
main
sebagai fungsi utama danexit_gracefully
sebagai CTRL+ cpenangansumber
Saya mengadaptasi kode dari @udi untuk mendukung beberapa sinyal (tidak ada yang mewah):
Kode ini mendukung panggilan interupsi keyboard (
SIGINT
) danSIGTERM
(kill <process>
)sumber
Berbeda dengan Matt J jawabannya, saya menggunakan objek sederhana. Ini memberi saya kemungkinan untuk mengurai handler ini ke semua utas yang perlu dihentikan keamanannya.
Di tempat lain
sumber
time.sleep()
bukannya melakukan loop sibuk pada suatu variabel.Anda dapat menggunakan fungsi-fungsi dalam modul sinyal built-in Python untuk mengatur penangan sinyal dengan python. Secara khusus
signal.signal(signalnum, handler)
fungsi ini digunakan untuk mendaftarkanhandler
fungsi untuk sinyalsignalnum
.sumber
terima kasih atas jawaban yang ada, tetapi ditambahkan
signal.getsignal()
sumber
Jika Anda ingin memastikan bahwa proses pembersihan Anda selesai, saya akan menambahkan jawaban Matt J dengan menggunakan SIG_IGN sehingga lebih lanjut
SIGINT
diabaikan yang akan mencegah pembersihan Anda terganggu.sumber
Secara pribadi, saya tidak bisa menggunakan try / kecuali KeyboardInterrupt karena saya menggunakan mode standard socket (IPC) yang memblokir. Jadi SIGINT dikeluarkan, tetapi datang hanya setelah menerima data pada soket.
Mengatur pengatur sinyal berperilaku sama.
Di sisi lain, ini hanya berfungsi untuk terminal aktual. Lingkungan awal lainnya mungkin tidak menerima Ctrl+C , atau menangani sinyal sebelumnya.
Juga, ada "Pengecualian" dan "BaseExceptions" dalam Python, yang berbeda dalam arti bahwa penerjemah perlu keluar dengan bersih sendiri, sehingga beberapa pengecualian memiliki prioritas yang lebih tinggi daripada yang lain (Pengecualian berasal dari BaseException)
sumber