【问题标题】:Using variables in signal handler - require global?在信号处理程序中使用变量 - 需要全局?
【发布时间】:2012-09-11 13:54:39
【问题描述】:

我有一个信号处理程序来处理 ctrl-c 中断。如果在信号处理程序中我想读取在我的主脚本中设置的变量,在设置变量时是否可以使用“全局”语句?

我不介意这样做,但请阅读这篇文章 (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()

【问题讨论】:

    标签: python


    【解决方案1】:

    您可以使用闭包作为从主脚本获取其状态的信号处理程序:

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

    【讨论】:

    • 好的,我想我的问题是信号处理程序是在主函数之外定义的。我没有充分的理由这样做,所以我认为我只需要移动它
    • 我想没有充分的理由通常是为什么全局变量可以移动到更受限制的范围! :)
    • 从外部范围修改变量并不像人们预期的那样工作。一种解决方法是传递一个引用,例如一个字典,其中包含对要修改的变量的引用。
    • @alexei 或在 python3 中使用nonlocal
    • @alexei 是正确的,局部变量不能跨范围修改。你可以阅读它,只是不能修改它。我不知道为什么对闭包示例进行了投票 - 闭包 var 仍然是本地的,并且会在处理程序退出时消失。 @henry - 是的,使用 nonlocal 关键字会在更大的范围内找到变量,因此这是一个修复,无需使变量成为全局变量。我喜欢 @Maxim 类示例作为跨方法使用变量的好/干净的方式....
    【解决方案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】:

      在面向对象范式 (OOP) 中,为此目的使用 lambda 非常方便。使用 lambda,您可以传递一些额外的上下文(如 self 引用)和/或摆脱未使用的参数(signalframe)。

      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 ..." )
      

      【讨论】:

        【解决方案4】:

        如果您只是读取变量,则不需要将变量设置为“全局”

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

        全局是允许您更改变量并将该更改传播到模块命名空间所必需的。

        如果你想在不使用全局的情况下将一些状态传递给你的回调,典型的做法是使用实​​例方法作为回调:

        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
        

        【讨论】:

        • 我很清楚他不是在谈论“全局”Python 关键字,而是在全局范围内(在模块范围内定义)的要求。这个答案没有帮助。
        【解决方案5】:

        您可以从内联定义的函数中访问外部范围变量,如下所示:

        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)
        

        【讨论】:

        • 刚刚评论了类似的回复:我认为我的问题是信号处理程序是在主函数之外定义的。我没有充分的理由这样做,所以我认为我只需要移动它
        • 如果 handler() 是在你自己的模块中定义的,这将如何工作?有理由这样做吗?只是好奇。
        猜你喜欢
        • 1970-01-01
        • 2013-08-16
        • 2013-03-08
        • 2016-08-13
        • 2018-06-17
        • 2021-07-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多