views:

153

answers:

2

I have a program which takes a long time to complete. I would like it to be able to catch SIGINT (ctrl-c) and call the self.save_work() method.

As it stands, my signal_hander() does not work since self is not defined by the time the program reaches signal_handler().

How can I set it up so self.save_work gets called after a 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()
A: 
def signal_handler(signal, frame):    
   #do some stuff

def main():
   #do some more stuff


if __name__=='__main__':
    signal.signal(signal.SIGINT, signal_handler)
    main()
jldupont
+4  A: 

If you just want to catch ctr+c then you can catch the KeyboardInterrupt exception:

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()

Not that I think this is a good design after all. It looks like you need to be using a function instead of a constructor.

Nadia Alramli
... assuming KeyboardInterrupt is thrown. I had occasions where it wasn't. Yet, sigint could be handled. Had to do with threads and blocking operations as far as I can remember. Unless I had borked my code somewhere else ;)
exhuma
@exhuma, the OP case seems simple enough. And yes I think I've encountered this behavior before with threads.
Nadia Alramli
Thank you. KeyboardInterrupt is what I was looking for.Sometimes I use a class just to simplify the passing around of parameters, without using globals. Is this considered bad design?
unutbu
@~unutbu, In your case it is confusing. Main() is supposed to be creating an object. Yet in your case it is running the whole application. If you want to simplify the arguments passing you could use class methods and class variables instead of constructors.
Nadia Alramli
Thanks again. Would it be consider acceptable if I changed `__init__` to `run` and called `Main().run()`?
unutbu
@~unutbu, yes that seems good enough
Nadia Alramli