【问题标题】:How to run one last function before getting killed in Python?如何在被 Python 杀死之前运行最后一个函数?
【发布时间】:2009-05-30 20:22:53
【问题描述】:

有没有办法在运行中的 Python 脚本被其他脚本、键盘中断等杀死之前运行最后一个命令。

【问题讨论】:

    标签: python function interrupt exit


    【解决方案1】:
    import time
    
    try:
        time.sleep(10)
    finally:
        print "clean up"
        
    clean up
    Traceback (most recent call last):
      File "<stdin>", line 2, in <module>
    KeyboardInterrupt
    

    如果需要捕捉其他OS级别的中断,看信号模块:

    http://docs.python.org/library/signal.html

    信号示例

    from signal import *
    import sys, time
    
    def clean(*args):
        print "clean me"
        sys.exit(0)
    
    for sig in (SIGABRT, SIGBREAK, SIGILL, SIGINT, SIGSEGV, SIGTERM):
        signal(sig, clean)
    
    time.sleep(10)
    

    【讨论】:

    • 我不知道你为什么选择那个特定的集合,但是 SIGBREAK 在非 Windows Python 上不起作用,而且 SIGILL 是 SIGSEGV 可能不是你想要在没有充分理由的情况下被捕获的信号.
    • @Dave 只是一个例子。并且由 dan 决定他想要捕获哪些中断。
    • sys.exit(0) 有必要吗?我认为无论如何你的函数完成后python都会退出。你用它来表明它是一个处理过的终止吗?
    • -1 表示奇怪和任意的信号集,正如@Dave 所指出的。使用SIGTERM 是有意义的(因为它的目的是指示进程退出),并且使用SIGUSR1 是合理的(因为它用于用户定义的操作),但是其中包含SIGILL 这样的东西是不合逻辑的。此外,这只是部分回答了这个问题;它不会处理脚本被键盘中断杀死的情况,这是问题中包含的一种可能性。
    【解决方案2】:

    您可以使用atexit 模块。使用它,您可以注册一个将在程序终止时调用的函数。此处的示例:http://docs.python.org/library/atexit.html

    try:
        _count = int(open("/tmp/counter").read())
    except IOError:
        _count = 0
    
    def incrcounter(n):
        global _count
        _count = _count + n
    
    def savecounter():
        open("/tmp/counter", "w").write("%d" % _count)
    
    import atexit
    atexit.register(savecounter)
    

    您还可以将位置和关键字参数传递给您要在程序终止时调用的函数。

    请注意,文档中列出了一些不会调用您的处理程序的情况:

    注意:当程序被 Python 未处理的信号杀死、检测到 Python 致命内部错误或调用 os._exit() 时,不会调用通过此模块注册的函数.

    因此,您可能还想注册一个信号处理程序。

    【讨论】:

      【解决方案3】:
      import signal
      import sys
      import time
      
      def cleanup(*args):
          print 'Exiting'
          sys.exit(0)
      
      signal.signal(signal.SIGINT, cleanup)
      signal.signal(signal.SIGTERM, cleanup)
      while True:
          time.sleep(60)  # less busy loop
      

      【讨论】:

      • 注意:虽然 exit() 在 C 语言中不是异步安全的,但 Python 文档的措辞向我表明 Python 通过一些特殊的信号处理代码来解决这个问题。
      • 我在 Windows XP 上测试过这段代码,实际上是因为 time.sleep() 被中断而引发了一个错误。它适用于 GNU/Linux。
      【解决方案4】:

      向“未知”道歉,因为他们接受了他们的答案并更正了它,就好像这是我自己的答案一样,但我的编辑被拒绝了。

      批准的答案包含会导致段错误的错误。

      您不能在信号处理程序中使用 sys.exit(),但可以使用 os._exit 使其变为:

      from signal import *
      import os, time
      
      def clean(*args):
          print "clean me"
          os._exit(0)
      
      for sig in (SIGABRT, SIGINT, SIGTERM):
          signal(sig, clean)
      
      time.sleep(10)
      

      如果目标平台是 Windows,则可以使用 SIGBREAK。

      根据用例和在发生致命错误时清理的需要 - 您可以添加 SIGSEGV 和 SIGILL,但通常不建议这样做,因为程序状态可能会导致您创建无限循环。

      【讨论】:

      • “批准的答案包含会导致段错误的错误。” - 错误是什么? sys.exit()的用途?它对我来说没有段错误;我需要做什么才能看到这个段错误? “您不能在信号处理程序中使用 sys.exit()” - 它似乎对我有用;你这样做的依据是什么?由于此答案中的关键主张未经证实,因此暂时谨慎 -1。
      • 不保证崩溃,基本上从 sys.exit() 引发异常的行为是未定义的。看到的各种行为包括崩溃 (stackoverflow.com/questions/24789269/…) 或退出调用似乎根本不起作用 (stackoverflow.com/questions/29980078/…)。另见thushw.blogspot.co.uk/2010/12/…
      • 您也没有在 SIGSEGV/SIGILL 上确认我的 cmets,这在接受的答案中也不正确。
      • @StuartM 似乎该博客文章中的问题是由except: 捕获SystemExit 引起的。请您详细说明“从 sys.exit() 引发异常的行为未定义”是什么意思?我不确定我是否理解你。
      【解决方案5】:

      使用 atexit 模块注册一个将在最后调用的函数。

      import atexit
      atexit.register(some_function)
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-12-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多