2009-11-04 4 views
4

J'ai un programme qui prend beaucoup de temps à terminer. Je voudrais pour être en mesure d'attraper SIGINT (ctrl-c) et appeler la méthode self.save_work().Enregistrement du travail après un SIGINT

En l'état actuel, mon signal_hander() ne fonctionne pas depuis self n'est pas défini au moment où le programme atteint signal_handler().

Comment puis-je le configurer afin que self.save_work soit appelé après un SIGINT?

#!/usr/bin/env python 
import signal 

def signal_handler(signal, frame):  
    self.save_work() # Does not work 
    exit(1) 
signal.signal(signal.SIGINT, signal_handler) 

class Main(object): 
    def do_stuff(self): 
     ... 
    def save_work(self): 
     ... 
    def __init__(self): 
     self.do_stuff() 
     self.save_work() 

if __name__=='__main__': 
    Main() 
+1

D'une part, vous ne pouvez pas utiliser "self" dans une fonction. – jldupont

Répondre

4

Si vous voulez juste attraper ctr + c vous pouvez attraper l'exception KeyboardInterrupt:

class Main(object): 
    def do_stuff(self): 
     ... 
    def save_work(self): 
     ... 
    def __init__(self): 
     try: 
      self.do_stuff() 
     except KeyboardInterrupt: 
      pass # Or print helpful info 
     self.save_work() 

Non pas que je pense que cela est une bonne conception après tout. Il semble que vous ayez besoin d'utiliser une fonction au lieu d'un constructeur.

+0

... en supposant que KeyboardInterrupt est lancé. J'ai eu des occasions où ce n'était pas. Pourtant, sigint pourrait être manipulé. J'ai eu à faire avec les threads et les opérations de blocage autant que je me souvienne. À moins que j'aie bougé mon code quelque part ailleurs;) – exhuma

+0

@exhuma, l'affaire OP semble assez simple. Et oui je pense avoir déjà rencontré ce comportement avec des threads. –

+0

Merci. KeyboardInterrupt est ce que je cherchais. Parfois, j'utilise une classe juste pour simplifier le transfert des paramètres, sans utiliser de globales. Est-ce considéré comme un mauvais design? – unutbu

2
import signal 

def signal_handler(signal, frame):  
    #do some stuff 

def main(): 
    #do some more stuff 


if __name__=='__main__': 
    signal.signal(signal.SIGINT, signal_handler) 
    main() 
+0

Vous devez d'abord 'importer le signal ' –

3

Habituellement, le «travail» implique une sorte de grosse boucle. Pour apprivoiser votre boucle, et l'empêcher de se casser dans une étape inconnue, vous pouvez utiliser le gestionnaire de contexte suivant:

import signal 

class GracefulInterruptHandler(object): 

    def __init__(self, sig=signal.SIGINT): 
     self.sig = sig 

    def __enter__(self): 

     self.interrupted = False 
     self.released = False 

     self.original_handler = signal.getsignal(self.sig) 

     def handler(signum, frame): 
      self.release() 
      self.interrupted = True 

     signal.signal(self.sig, handler) 

     return self 

    def __exit__(self, type, value, tb): 
     self.release() 

    def release(self): 

     if self.released: 
      return False 

     signal.signal(self.sig, self.original_handler) 

     self.released = True 

     return True 

Pour utiliser:

import time 

/// do stuff: 
with GracefulInterruptHandler() as h: 
    for i in xrange(1000): 
     print "..." 
     time.sleep(1) 
     if h.interrupted: 
      print "interrupted!" 
      time.sleep(5) 
      break 

save_work() 

D'ici: https://gist.github.com/2907502

Questions connexes