Использование переменных в обработчике сигналов - требуется глобальное?
У меня есть обработчик сигнала для обработки прерывания 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