PythonでUNIXシグナルのハンドラを扱う(前半)
Traceback (most recent call last): File "[スクリプトの場所]", line xxx, in <module> app.main() File "[スクリプトの場所]", line xxx, in main gtk.main() KeyboardInterrupt
のようにKeyboardInterrupt例外が発生してメッセージが表示され、PyGTKを用いたGUIアプリケーションでもこのようにメッセージが表示される。C言語やVala言語などでGTK+を用いたプログラムを作成した場合にはこのようにはならないが、PyGTKでこのメッセージが出るのが邪魔な場合、抑制することはできる。
PythonにおけるUNIXシグナルの処理
一般的に、GNU/Linux上のアプリケーションは、UNIXシグナルを受け取ったときに任意のハンドラ関数を呼び出すように関連付けることができる。
これはOSの機能(システムコール)のsignal()にシグナルの識別番号とハンドラ関数の場所を指定することで行うが、Pythonではsignalというモジュールのsignal.signal()を用いて同様の要領でハンドラを指定できる。
ハンドラは2つの引数を受け取るようにしておく。1つ目の引数にシグナルの識別値が入る。
# シグナルSIGINT(Ctrl+Cなどで発生)を受け取ったときに関数func()を呼ぶ signal.signal(signal.SIGINT, func) ... def func(num, frame): """ UNIXシグナルのハンドラ 引数は2つ・番号とフレームオブジェクト """ print 'func(): %d, %s' % (num, str(frame)) # ここではSIGINTの数値がnumに入る
テスト
下のコードを端末上で実行しCtrl+Cを押すと
func(): 2, <frame object at 0x122dbc0>
のような出力をして終了する。
#! /usr/bin/python # -*- encoding: utf-8 -*- import signal import sys import os try: import pygtk pygtk.require('2.0') except: pass try: import gtk except: sys.exit(1) class MainWindow(gtk.Window): """ メインウィンドウ """ def __init__(self, *args, **kwargs): gtk.Window.__init__(self, *args, **kwargs) self.set_title('test') self.set_size_request(320, 200) self.__accelgroup = gtk.AccelGroup() self.add_accel_group(self.__accelgroup) self.__item_quit = gtk.ImageMenuItem(gtk.STOCK_QUIT, self.__accelgroup) self.__menu_file = gtk.Menu() self.__menu_file.add(self.__item_quit) self.__item_file = gtk.MenuItem('_File') self.__item_file.set_submenu(self.__menu_file) self.__menubar = gtk.MenuBar() self.__menubar.append(self.__item_file) self.__button = gtk.Button() self.__button.set_label('Test') self.__statusbar = gtk.Statusbar() self.__vbox = gtk.VBox(False, 0) self.__vbox.pack_start(self.__menubar, expand=False, fill=False) self.__vbox.pack_start(self.__button) self.__vbox.pack_start(self.__statusbar, expand=False, fill=False) self.add(self.__vbox) self.__button.connect('clicked', self.__on_button_clicked) self.__item_quit.connect('activate', gtk.main_quit) self.connect('delete_event', gtk.main_quit) def __on_button_clicked(self, widget): """ ボタンが押されたときの処理 """ print '__on_button_clicked()' class PyGTKUnixSigHandlerTest: """ UNIXシグナルハンドラのテスト """ def main(self): """ ウィンドウを作成してGTK+のメインループを呼ぶ """ # シグナルSIGINT(Ctrl+Cなどで発生)を受け取ったときに関数func()を呼ぶ signal.signal(signal.SIGINT, func) win = MainWindow() win.show_all() gtk.main() def func(num, frame): """ UNIXシグナルSIGINTのハンドラ 引数は2つ・番号とフレームオブジェクト """ print 'func(): %d, %s' % (num, str(frame)) # ここではSIGINTの数値がnumに入る # メインループを抜けて終了することにする gtk.main_quit() if __name__ == '__main__': app = PyGTKUnixSigHandlerTest() app.main()
(2010/2/9)後半の形に合わせて書き方を微調整(動作は同じ)
(「PythonでUNIXシグナルのハンドラを扱う(後半)」に続く)
関連記事:
- シェル上のプロセスの動作状態(フォアグラウンド/バックグラウンド/サスペンド)とその制御について(前半)
- シェル上のプロセスの動作状態(フォアグラウンド/バックグラウンド/サスペンド)とその制御について(後半)
- UNIXシグナルによるプロセス制御について
- PythonでUNIXシグナルのハンドラを扱う(後半)
参考URL: