在信号处理程序中使用变量 - 需要全局变量吗?
在信号处理程序中使用变量 - 需要全局变量吗?
我有一个信号处理程序来处理ctrl-c中断。如果在信号处理程序中,我想读取在我的主脚本中设置的变量,是否有不使用"global"语句的替代方法?
我不介意这样做,但在这篇帖子中(Do you use the "global" statement in Python?),有人评论说不应该有任何理由使用global。
在这种情况下有什么替代方法?
我的代码看起来像这样:
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()
在上述代码中,问题的原因是信号处理程序(signal handler)被定义在主函数(main_function)之外。这样做没有一个好的理由,所以需要将其移动到主函数中。
解决方法是将信号处理程序定义为主函数的内部函数,并在主函数中设置信号处理函数。这样,信号处理程序可以访问并修改主函数中的局部变量。
以下是修改后的代码示例:
import signal import sys import time def main_function(): data_for_signal_handler = 10 def signal_handler(*args): nonlocal data_for_signal_handler 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()
在修改后的代码中,信号处理程序(signal_handler)使用了`nonlocal`关键字来引用主函数(main_function)中的局部变量`data_for_signal_handler`。这样就可以在信号处理程序中访问和修改该变量。
通过将信号处理程序定义为主函数的内部函数,并使用`nonlocal`关键字来引用主函数中的局部变量,解决了在信号处理程序中使用变量的问题,而无需将变量设为全局变量。
在面向对象的编程范式中,使用lambda函数非常方便。使用lambda函数可以传递一些额外的上下文(比如self引用),并且可以摆脱未使用的参数(signal和frame)。
上面的代码是一个简单的应用程序,其中包含一个signal_handler函数。在初始化Application对象时,使用signal.signal函数将SIGINT信号与lambda函数绑定。lambda函数在接收到SIGINT信号时调用_signal_handler函数,该函数将self.terminated变量设置为True。
MainLoop函数是一个循环,只有当self.terminated变量为False时才会执行。循环中每隔3秒打印一条消息。直到self.terminated变量为True,循环才会终止。
当运行这段代码时,我们可以看到应用程序在终止之前会一直输出消息。当我们按下CTRL+C时,应用程序接收到SIGINT信号,lambda函数被调用,将self.terminated变量设置为True。然后MainLoop函数检测到self.terminated为True,循环结束,应用程序终止。
原因:
问题是在信号处理程序中使用了lambda函数,并且该lambda函数使用了self引用。由于lambda函数是在初始化对象时创建的,它没有访问对象的上下文,因此无法使用self引用。这导致在信号处理程序中无法正确访问和操作对象的属性。
解决方法:
为了解决这个问题,我们可以使用一个全局变量来存储对象的引用,然后在lambda函数中使用这个全局变量。
下面是修改后的代码:
import time import signal class Application: def __init__( self ): signal.signal( signal.SIGINT, lambda signal, frame: signal_handler() ) self.terminated = False def signal_handler(): global app app._signal_handler() 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() global app app.MainLoop() print( "The app is terminated, exiting ..." )
在修改后的代码中,我们在signal_handler函数中使用了一个全局变量app,该变量存储了Application对象的引用。然后在lambda函数中调用signal_handler函数,通过全局变量app来访问和操作对象的属性。这样就可以正确地在信号处理程序中使用对象的属性了。
通过这种方式,我们可以在信号处理程序中正确地使用对象的属性,实现了在lambda函数中使用self引用的目的。
使用变量在信号处理程序中 - 需要全局变量吗?
在上面的代码中,我们定义了一个信号处理函数signal_handler和一个主函数main。在主函数中,我们定义了一个全局变量g_var,并将其传递给signal.signal函数。
问题的原因是,信号处理函数signal_handler无法直接访问主函数main中定义的局部变量g_var。这是因为信号处理函数是在一个独立的上下文中执行的,与主函数main不在同一个上下文中。
为了解决这个问题,我们可以使用partial函数来创建一个“闭包”。partial函数可以将一个函数与一组固定的参数绑定在一起,并返回一个新的函数。在这种情况下,我们将g_var作为参数传递给partial函数,然后将返回的函数作为信号处理函数传递给signal.signal函数。这样,当信号处理函数被调用时,它将能够访问到g_var这个变量。
解决方法如下:
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()
在这个解决方案中,我们首先导入了signal和functools模块。然后,我们定义了信号处理函数signal_handler,它接受三个参数:g_var、signal和frame。在函数中,我们打印出g_var的值。
接下来,我们定义了主函数main,在函数中我们定义了局部变量g_var,并将其传递给partial函数。partial函数将g_var与signal_handler函数绑定在一起,并返回一个新的函数。
最后,我们使用signal.signal函数将返回的函数作为信号处理函数传递给SIGINT信号。这样,当接收到SIGINT信号时,信号处理函数signal_handler将被调用,并打印出g_var的值。
通过使用partial函数,我们成功地解决了在信号处理函数中访问局部变量的问题。现在,信号处理函数能够访问和使用主函数中定义的局部变量g_var了。