捕获Python异常并打印出单独的消息

时间:2014-11-25 02:51:21

标签: python python-2.7 exception exception-handling drmaa

我目前正在尝试编写代码来捕获异常,并且根据抛出的异常,将导入与未抛出异常时不同的模块。

try:
  import sge_execution_engine as execution_engine
except ImportError: 
  print "Use local execution engine because SGE support is missing!"
  print sys.exc_info() # Print out the exception message
  import local_execution_engine as execution_engine
except RuntimeError:
  print "Using local execution engine because SGE support is missing!"
  print sys.exc_info()
  import local_execution_engine as execution_engine

捕获的第一个异常ImportError捕获在drmaa执行期间无法找到python import sge_execution_engine模块时抛出的异常(在sge_execution_engine内,有import drmaa声明。找到RuntimeError python库时会捕获第二个异常drmaa(在import drmaa内执行sge_execution_engine语句期间喜欢这样,但{{1} C库未安装到操作系统中。我们希望这两个drmaa语句足以捕获当用户尝试在没有python except库的机器上运行此模块时可能抛出的所有可能异常,{{ 1}} C库,或者没有安装Sun Grid Engine。如果没有任何这些收益,模块将继续进行drmaa,因此代码可以在本地在用户的机器上执行。现在,代码按预期工作,因为它在使用sge找到异常时导入本地,但我们仍然希望在此处改进异常处理以使其更加健壮。

在我看来,我认为将抛出的实际异常消息打印到stdout是好的,因为它将允许用户知道他无法导入sge_execution_engine的原因,特别是如果他不期望它导入失败。

然而,我没有使用drmaa来实际在屏幕上显示实际的异常消息,而是意识到可能更好的方法是使用import local_execution_engine格式然后打印出来{{1并且还调用与抛出并分配给print sys.exc_info()的异常相关联的一些属性。

我看到这是在Python tutorial on exceptions里完成的,那里有一大堆代码:

except EXCEPTION as some_variable_name

似乎print some_variable_name块通过专门调用some_variable_name对象的import sys try: f = open('myfile.txt') s = f.readline() i = int(s.strip()) except IOError as e: print "I/O error({0}): {1}".format(e.errno, e.strerror) except ValueError: print "Could not convert data to an integer." except: print "Unexpected error:", sys.exc_info()[0] raise except IOError as e属性,以细粒度的方式处理异常消息。但是,当我查看errno documentation时,我没有看到这些特定属性被列为异常文档的一部分。实际上,对于Python文档中的所有其他异常也是如此,因此我们似乎无法确定哪些属性将与特定异常相关联。如果我们对此一无所知,那么当我们使用strerror语法处理异常时,我们如何能够找出在IOError对象上调用哪些属性?

我很感激任何人对此的建议,即使你的答案没有直接回答我的问题,但如果你对我如何更好地处理我的例外情况有另一个完全不同的建议,请不要这样做。犹豫要发帖!

非常感谢!

2 个答案:

答案 0 :(得分:0)

首先你是对的,最好将异常捕获到一个变量而不是忽略它,然后用sys.exc_info()将其拉回来。有一些很好的理由可以使用exc_info(低级代码,必须与2.6之前和3.x之间的代码一起工作的代码等),但一般来说,当你得到的可以按照你的方式去做,你应该。

这甚至可以用于你的最后一次除外。在2.7中,普通except:表示与except Exception:相同,因此您可以编写except Exception as e:,然后使用e值。

另请注意,如果您希望针对多种异常类型执行完全相同的操作,则可以编写except (RuntimeError, ImportError) as e:

至于“让它变得更强大”,这不是绝对的事情。例如,如果有一些意外的异常既不是RuntimeError也不是ImportError,您是否要记录它并尝试回退代码,或者完全转储回溯?如果它是,例如由某人检查您的程序的错误编辑导致的SyntaxError,您可能不希望将其视为运行时错误...或者您可能会这样做;这实际上取决于您的开发实践和目标用户群。


同时

  

似乎except IOError as e块通过专门调用errno对象的strerrorIOError属性,以细粒度的方式处理异常消息。但是,当我查看IOError documentation时,我没有看到这些特定属性被列为异常文档的一部分。

您需要查找hierarchy。请注意,IOErrorEnvironmentError的子类,它会记录errnostrerror属性。 (这些属性实际上意味着的内容仅针对OSError及其子类进行了文档记录,但它们存在的事实已记录在案。)

如果你认为这有点乱......嗯,确实如此。它全部在Python 3.x中清理,其中IOErrorEnvironmentError合并到OSError,它清楚地记录了它的属性,并且你通常不需要打开{{ 1}}首先是因为常见errno值会生成特定的子类,如errno,依此类推。但是只要你使用2.7,你就无法获得过去6年语言改进的好处。


  

例如,查看层次结构或FileNotFoundError(层次结构中从最低到最高),我找不到任何关于它的属性。

如果你ValueError=>StandardError=>Exception dir,你会发现它只有两个属性(除了通常的特殊内容,如ValueError__repr__):{{1 }和__class_

args未记录,因为它在2.5中已弃用,并且仅存在于2.7中以允许某些2.5版之前的代码继续运行。*但是message已记录在案;你只需要进一步上升到BaseException

  

message

     

赋予异常构造函数的参数元组。一些内置异常(如args)期望一定数量的参数并为此元组的元素赋予特殊含义,而其他异常通常仅使用单个字符串调用给出错误消息。

因此,您在args中找不到其他属性的原因是没有其他属性可供查找。其他课程也是如此。少数具有特殊属性的类型(IOErrorValueError,可能是stdlib中其他一些特定于模块的类型)明确记录它们。**

  

如果我们使用OSError语法,则执行SyntaxError足以在不调用其属性的情况下打印出异常

只需打印某些有用的异常形式就足够了。同样,来自except some_exception as e文档:

  

如果在此类的实例上调用print eBaseException,则返回实例的参数表示,或者在没有参数时返回空字符串。

在某些情况下,这不是你想要的。特别要注意,它不包含异常的类型。您可以使用str()来获取该内容,这会为您提供类似构造函数调用的内容(例如unicode())。

如果您希望获得与追溯相同的输出,则必须自己将reprValueError("invalid literal for int() with base 10: 'f'")type放在一起 - 例如,str。< / p>

如果你想从异常中获取实际信息,比如那个基数unicode或那个字符串'{}: {}'.format(type(e), e) - 嗯,你不能,***因为那个信息已经被抛出了远。您必须编写自己的代码来跟踪它,例如:

10

*好像'f'定义为try: i = int(s, 16) except ValueError as e: print '{} is not a base-16 number'.format(s)

**我相信在2.5中有一些异常类型具有未记录的属性作为CPython的实现细节,但是到2.7它们都已经消失或记录。

***嗯,你可以解析异常字符串,但不用说,这是一个实现细节,而不是保证稳定和可移植的东西。它可能在Jython或西班牙语系统中有所不同,或者它可能不会按照您期望的方式引用字符串等。

答案 1 :(得分:0)

使用裸except很少是一个好主意,但这是极少数情况之一 - 主要是因为如果由于某种原因导致您无法导入系统,则需要使用备份{ {1}}:

sge

请注意,您现在只需要一个try: import sge_execution_engine as execution_engine except: print "Use local execution engine because SGE support is missing!" print sys.exc_info() # Print out the exception message import local_execution_engine as execution_engine 子句。

处理向用户提供该信息的更好方法可能是继续打印出来,然后使用logging模块进行永久记录:

except

然后在你的import logging logger = logging.getLogger() logger.setLevel(logging.WARNING) 子句中添加:

except

并且您的消息以及实际异常将保存在日志文件中。