【问题标题】:Python Program is Terminating on Handled ExceptionPython 程序在处理异常时终止
【发布时间】:2013-02-22 19:52:48
【问题描述】:

为了清楚起见,我正在编辑问题。

我在导入 MySQLdb 的模块中创建了一个类。我发现如果用户传递给我的类的表不存在,MySQLdb 将引发异常。我正在捕获该异常,并将一个新异常传递给客户。但即使客户端捕捉到我的异常,程序仍然会终止。我也尝试将相同的异常 MySQLdb 传递给客户端。

由于客户端将在循环中调用我的方法,并传入各种表名,因此我不希望程序在表名错误时阻塞。我希望客户的迭代继续到下一个有效的表名。这是一个 sn-p(tableName 是传递给方法的 arg):

在我的班级/模块中:

self.tableName = 表名 尝试: self.cursor.execute("select * from " + self.tableName + ";") #如果表不存在会抛出异常。 除了: raise MyException("\n*** " + self.tableName + " 不存在。***")

在客户端:

表 = ["BadTableName", "GoodTableNameA", "GoodTableNameB","GoodTableNameC"] 尝试: 对于表格中的表格: my_method(table) #Exception 消息通过 BadTableName 传入,但程序结束。此循环的子序列迭代永远不会发生 除了例外,e: 打印 e

我希望客户端在调用 my_method(BadTableName) 之后继续。

顺便说一句,my_method() 是在其自己的模块中定义的类的一部分,客户端正在导入该类。

谢谢。

【问题讨论】:

  • MyException 是继承自 Exception 还是其他?你使用的是哪个版本的 Python?

标签: python exception


【解决方案1】:

异常并不总是导致程序结束。来自docs

在执行过程中检测到的错误称为异常,而不是 无条件致命:

如果在 try: except 块中引发异常并且 except 子句指定异常或异常的超类,它将被处理。

在处理异常时,您可以检查它并找出与之相关的所有信息。我以前从未使用过traceback 模块,但它看起来包含您需要的一切。

我想您的第二个问题取决于您希望用户看到的内容。是否应该显示异常? (您可以访问回溯)。应该只显示消息吗?你应该记录回溯吗?

【讨论】:

    【解决方案2】:

    添加到其他答案:未捕获的异常将终止程序,但仅在执行适用的finally block(如果有)和任何atexit handlers 之后。所以原则上,可以在未捕获的异常之后无限期地继续执行。

    不过,没有哪类异常只会打印错误消息并按其性质继续执行。如果需要,请使用warnings

    【讨论】:

      【解决方案3】:

      阅读您编辑的问题后,我不确定您遇到了两个问题中的哪一个。


      如果您的问题只是您想要一个异常仅终止一个循环迭代而不是整个循环,那么只需以明显的方式重新嵌套语句即可。而不是这个:

      try:
          for table in tables:
              my_method(table) #Exception message gets passed in with BadTableName, but the program ends. Subsequest iterations of this loop never happen
      except Exception, e:
          print e
      

      这样做:

      for table in tables:
          try:
              my_method(table) #Exception message gets passed in with BadTableName, but the program ends. Subsequest iterations of this loop never happen
          except Exception, e:
              print e
      

      另一方面,如果问题是客户端没有捕获异常,那么问题很可能是您的MyException 不是Exception 的子类。至少有三种方式会发生这种情况。

      由于您使用的是旧式 except 语法 (except Exception, e:) 而不是新式 (except Exception as e:),因此您可能使用的是较旧的 Python 版本,它允许您引发不继承自BaseException。例如:

      class MyException(object):
          def __init__(self, msg):
              pass
      
      try:
          raise MyException("dsfsdf")
      except Exception:
          pass
      

      根据您的 Python 版本,这可能无法引发 MyException 而是引发 TypeError(' Out[11]: TypeError('exceptions must be old-style classes or derived from BaseException, not MyException')(这将被捕获),或者打印警告,或者只是按照您的要求默默地“工作”(意思是你什么也抓不到,你的程序退出并回溯)。


      同时,即使在 2.7 中,您仍然可以提出旧式类,也不会被捕获:

      class MyException:
          def __init__(self, msg):
              pass
      
      try:
          raise MyException("dsfsdf")
      except Exception:
          pass
      

      这将始终无法捕获异常,并且您的应用将退出并带有回溯。


      最后,如果你继承自BaseException 而不是Exception,那么显然Exception 不会捕获它。

      class MyException(BaseException):
          def __init__(self, msg):
              pass
      
      try:
          raise MyException("dsfsdf")
      except Exception:
          pass
      

      再一次,这将始终无法捕获您提出的内容,并且您将退出并进行回溯。

      【讨论】:

      • 感谢 abarnert - 提供答案,并花时间重新阅读我编辑的问题。解决方案是您为我的问题提出的两个原因中的第一个。以(现在非常)明显的方式重新嵌套语句有帮助。再次感谢!
      • @RLS:是的,这种东西一看到就很明显,但以前可能不明显……
      【解决方案4】:

      1) 不,引发异常并不总是会导致程序终止。 未捕获 异常会导致程序终止。您可以使用try/except 块包围代码,如下所示,以阻止异常向上传播。

      try:
          file = open("foo.txt")
      except IOError:
          file = None
      

      2) 实际捕获异常的代码可以访问异常的原始堆栈帧,并且可以决定如何处理它。

      使用原始回溯重新引发错误:

      try:
          some_function()
      except IOError as e:
          raise
      

      使用新的回溯重新引发错误(几乎没有第一种情况有用):

      try:
          some_function()
      except IOError as e:
          raise e
      

      不要重新引发,并打印异常和回溯:

      try:
          some_function()
      except IOError as e:
          import traceback
          traceback.print_exc()
      

      【讨论】:

      • 感谢您的回答。不幸的是,我的问题不是很清楚。为了清楚起见,我对其进行了编辑。请查看已编辑的问题。
      【解决方案5】:

      未捕获异常将终止程序。 捕获的异常不会

      如果捕获到异常,可以使用traceback模块输出堆栈跟踪:

      http://docs.python.org/2/library/traceback.html#traceback-examples

      【讨论】:

        猜你喜欢
        • 2017-08-13
        • 1970-01-01
        • 1970-01-01
        • 2016-09-21
        • 2012-01-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多