views:

98

answers:

2

I am trying to get up to speed with Python, trying to replace some C with it. I have run into a problem with sharing data between modules, or more likely my understanding of the whole thing. I have a signal module which simplified is:

import sys, signal

sigterm_caught = False

def SignalHandler(signum, stackframe):
  if signum == signal.SIGTERM:
    sigterm_caught = True
    sys.stdout.write("SIGTERM caught\n")

def SignalSetup():
  signal.signal(signal.SIGTERM, SignalHandler)

and my main code has a loop like this:

signals.SignalSetup()
while signals.sigterm_caught == False:
  sys.stdout.write("sigterm_caught=%s\n" % str(signals.sigterm_caught))
  time.sleep(5)

I run it, then kill the process, inside signals.py it gets the signal, sets sigterm_caught to True, but the loop in the main process does not see a change in value of sigterm_caught.

So (a) is my approach completely wrong for the Python way? (b) am I doing something wrong in trying to reference variables in the module? and (c) should I be handling signals differently, like raising an exception?

Addition: Is it better to handle signals by raising an exception, or is my old C approach still a valid one?

+5  A: 

You need to add a global statement to the handler:

def SignalHandler(signum, stackframe):
  global sigterm_caught
  if signum == signal.SIGTERM:
    sigterm_caught = True
    sys.stdout.write("SIGTERM caught\n")

The Python compiler, by default, deems each name (like sigterm_caught) to be local to a function if it seems the function assign to the name; the role of the global statement is to reverse this default, so that the Python compiler will deem the name to be global (i.e., a module-level top name) instead.

Alex Martelli
That works. Thanks. I better go re-read about Python scope.
codebunny
Is it better to handle signals by raising an exception, or is the global variable method still valid?
codebunny
@codebunny, the only exception you should ever raise "asynchronously" (i.e., coming from an external cause unrelated to the code that's running) is `KeyboardInterrupt`; funneling all signals through that exception (or subclasses thereof) is a possibility, but IMHO, when feasible, your alternative is preferable (opinions may differ;-).
Alex Martelli
+3  A: 

If you are writing to a global variable, use global:

sigterm_caught = False

def SignalHandler(signum, stackframe):
  global sigterm_caught
  if signum == signal.SIGTERM:
    sigterm_caught = True
    sys.stdout.write("SIGTERM caught\n")
extraneon