在Python中处理除SIGINT之外的信号的“正确”方法?

时间:2012-11-14 11:16:57

标签: python signals

我有一些需要能够处理SIGINT的Python代码。为此,我使用了这样的东西:

def mymethod(*params):
  obj = MyObj(params)
  try:
    obj.do_some_long_stuff()
  except KeyboardInterrupt:
    obj.cleanup()

太棒了,真的很直白。是的,Python很棒!

但是,我现在还需要处理其他信号,即SIGTSTP和SIGQUIT。我正在尝试做的是类似的事情。这里有一些伪代码演示了我正在尝试用SIGTSTP做什么(我希望它足够清楚):

def mymethod(*params):
  obj = MyObj(params)
  try:
    obj.do_some_long_stuff()
  catch SIGINT:
    obj.cleanup()
  catch SIGTSTP:
    log_stop(obj) # Log that we stopped obj (add info about stop signal happening in obj-specific log file )
    raise SIGTSTP # Do normal SIGTSTP behavior as if we didn't catch the signal

这里的方法似乎是使用信号模块。但是,我的问题是我无法再使用KeyboardInterruptException来访问对象状态:

import os
import signal

def handler(signum, frame):
  print "I can't access obj from here anymore!" # How to access obj from here?
  signal.signal(signum, signal.SIG_DFL)
  os.kill(os.getpid(), signum) # Rethrow signal, this time without catching it

def mymethod(*params):
  obj = MyObj(params)
  signal.signal(signal.SIGTSTP, handler)
  obj.do_some_long_stuff()   

那么如何解决这个问题,即在仍然可以访问我正在使用的对象时处理信号呢?

2 个答案:

答案 0 :(得分:9)

或使用闭包:

import os
import signal

def create_handler(obj):
    def _handler(signum, frame):
        print "obj is availiable here!"
        print obj
        signal.signal(signum, signal.SIG_DFL)
        os.kill(os.getpid(), signum) # Rethrow signal, this time without catching it
    return _handler

def mymethod(*params):
  obj = MyObj(params)
  signal.signal(signal.SIGTSTP, create_handler(obj))
  obj.do_some_long_stuff()   

create_handler(obj)返回一个可以访问obj的处理函数。

答案 1 :(得分:1)

这可以在handler是一个类方法并且包含self-member的条件下工作。

你可以使obj成为全局,因为你可以从每个函数访问它。

import os
import signal
obj = None

def handler(signum, frame):
    log_stop(obj)
    signal.signal(signum, signal.SIG_DFL)
    os.kill(os.getpid(), signum) # Rethrow signal, this time without catching it

def mymethod(*params):
    global obj # to signal that the obj we are changing here is the global obj

    obj = MyObj(params)
    handler.obj = obj
    signal.signal(signal.SIGTSTP, handler)
    obj.do_some_long_stuff()

(注意:我个人尽可能避免使用全局参数,因为全局意味着真正的全局参数。)