Использование переменных в обработчике сигналов - требуется глобальное?

У меня есть обработчик сигнала для обработки прерывания ctrl-c. Если в обработчике сигнала я хочу прочитать набор переменных в моем главном script, есть ли альтернатива использованию "глобального" оператора при установке переменной?

Я не возражаю против этого, но прочитал это сообщение (Вы используете "глобальный" оператор в Python?), в котором кто-то прокомментировал, что не будет основанием для использования глобального.

Какова альтернатива в этом случае?

Мой код выглядит следующим образом:


def signal_handler(signal, frame):
    print "in sig handler - g_var=%s" % g_var

def main():
    global g_var
    g_var = "test"

    time.sleep(120)


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

Ответы

Ответ 1

Вы можете использовать замыкание как обработчик сигнала, который получает свое состояние из основного script:

import signal
import sys
import time

def main_function():

    data_for_signal_handler = 10

    def signal_handler(*args):
        print data_for_signal_handler
        sys.exit()

    signal.signal(signal.SIGINT, signal_handler) # Or whatever signal

    while True:
        data_for_signal_handler += 1
        time.sleep(0.5)

if __name__ == '__main__':
    main_function()

Ответ 2

Вы можете использовать partial для создания "закрытия".

import signal
from functools import partial

def signal_handler(g_var, signal, frame):
    print "in sig handler - g_var=%s" % g_var

def main():
    g_var = "test"
    signal.signal(signal.SIGINT, partial(signal_handler, g_var))

    time.sleep(120)


if __name__ == '__main__':
    main()

Ответ 3

Вы можете получить доступ к переменным внешней области видимости внутри встроенной функции, например:

my_values = {'foo':'bar'}
def handler(signum, frame):
    for key,val in my_values.items():
        print key,val
    my_values['bat']='baz'
    #remember to use mutable types, like dicts or lists

signal.signal(signal.SIGINT, handler)

Ответ 4

В рамках объектно-ориентированной парадигмы (ООП) довольно удобно использовать лямбда для этой цели. Используя lambdas, вы можете передать некоторый дополнительный контекст (например, саморегуляцию) и/или избавиться от неиспользуемых аргументов (сигнал, кадр).

import time
import signal

class Application:

    def __init__( self ):
        signal.signal( signal.SIGINT, lambda signal, frame: self._signal_handler() )
        self.terminated = False

    def _signal_handler( self ):
        self.terminated = True

    def MainLoop( self ):        
        while not self.terminated:
            print( "I'm just doing my job like everyone else" )
            time.sleep( 3 )

app = Application()
app.MainLoop()

print( "The app is terminated, exiting ..." )

Ответ 5

Если вы просто читаете переменную, не должно быть необходимости делать переменную "global"

def foo():
    print a
a = 3
foo()  #3

global необходим, чтобы вы могли изменить переменную и распространить это изменение на пространство имен модулей.

Если вы хотите передать какое-либо состояние вашему обратному вызову без использования глобального, типичный способ сделать это, чтобы мы использовали метод экземпляра в качестве обратного вызова:

class foo(object):
     def __init__(self,arg):
         self.arg = arg
     def callback_print_arg(self):
         print self.arg

def call_callback(callback):
    callback()

a = foo(42)
call_callback(a.callback_print_arg) #42