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

2024-05-17 15:06:03 发布

您现在位置:Python中文网/ 问答频道 /正文

我目前正在尝试编写代码来捕捉异常,根据抛出的异常,将导入一个与没有异常时不同的模块。在

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捕捉到在执行import sge_execution_engine期间找不到pythondrmaa模块时抛出的异常(在sge_execution_engine内部有一个import drmaa语句)。第二个异常是RuntimeError,当找到drmaapython库时(就像在执行sge_execution_engine内的import drmaa语句时),但是drmaaC库没有安装到操作系统中。我们希望这两条except语句足以捕获当用户试图在没有pythondrmaa库、drmaaC库或没有安装sungrid引擎的机器上运行该模块时可能引发的所有异常。如果没有这些进程,模块将继续执行import local_execution_engine,这样代码就可以在用户的机器上本地执行。现在,代码的工作与预期的一样,当它发现sge异常时,它将被导入本地,但是我们仍然希望改进这里的异常处理,使其更加健壮。在

在我看来,将抛出的实际异常消息打印到stdout是很好的,因为它可以让用户知道为什么他无法导入sge_execution_引擎,尤其是如果他不希望导入失败的话。在

然而,我没有使用print sys.exc_info()在屏幕上打印实际的异常消息,我意识到也许更好的方法是使用except EXCEPTION as some_variable_name格式,然后打印出print some_variable_name,同时调用与抛出并分配给some_variable_name的异常相关联的一些属性。在

我在Python tutorial on exceptions中看到了这一点,那里有一段代码:

^{pr2}$

似乎except IOError as e块是通过专门调用errno和{}对象的errno和{}属性,以细粒度的方式处理异常消息。但是,当我查看IOErrordocumentation时,我没有看到这些特定属性作为异常文档的一部分列出。事实上,Python文档中的所有其他异常也是如此,因此我们似乎无法确定哪些属性将与特定异常关联。如果我们对此一无所知,那么当我们使用import EXCEPTION as some_variable_name语法来处理异常时,我们将如何确定对some_variable_name对象调用什么属性?在

如果你的回答没有直接回答我的问题,我将非常感谢任何人的建议,但是如果你对我如何更好地处理我的异常有另一个完全不同的建议,请不要犹豫,发一个帖子!在

非常感谢!在


Tags: 模块代码nameimport属性localassys
2条回答

首先,您是对的,将异常捕捉到变量中比忽略它然后用sys.exc_info()将其拉回来要好。使用exc_info(低级代码,必须同时使用pre-2.6和3.x版本的代码,等等)有一些很好的理由,但是一般来说,当你能用你自己的方式去做时,你应该这样做。在

这对你的最后一次赤身裸体也是有效的。在2.7中,一个普通的except:except Exception:的意思是一样的,所以你可以写except Exception as e:,然后使用e值。在

还要注意,如果您想对多个异常类型执行完全相同的操作,可以编写except (RuntimeError, ImportError) as e:。在

至于“让它更强大”,这不是绝对的事情。例如,如果有一些意外的异常既不是RuntimeError,也不是ImportError,那么您是要记录它并尝试回退代码,还是完全并转储回溯?如果它是由某人在你的程序中签入了一个错误的编辑而引起的SyntaxError,你可能不想把它当作运行时错误来处理……或者也许你会这样做;这实际上取决于你的开发实践和目标用户群。在


同时:

It seems like the except IOError as e chunk is handling the exception message in a fine-grained way by specifically calling on the errno and strerror attributes of the IOError object. However, when I look at the IOError documentation, I do not see these specific attributes being listed out as part of the documentation for the exception.

您需要查找hierarchy。注意,IOError^{}的子类,它记录了errno和{}属性。(这些属性实际上意味着什么只是针对OSError及其子类的文档,但它们存在的事实是有文档记录的。)

如果你觉得这有点乱…嗯,是的。在python3.x中,所有这些都被清理干净了,其中IOError和{}被合并到OSError中,这清楚地记录了它的属性,而且通常您不必首先打开errno,因为通用的errno值会生成一个特定的子类,比如FileNotFoundError,依此类推。但只要你用的是2.7,你就得不到过去6年语言改进的好处。在


For example, looking at the hierarchy or ValueError=>StandardError=>Exception (from lowest to highest in the hierarchy), I can't find any attributes about it.

如果您dir一个ValueError,您将看到它只有两个属性(除了通常的特殊属性,如__repr__和{}):args和{}。在

message未被记录,因为它在2.5中已被弃用,并且只存在于2.7中,以允许某些2.5之前的代码继续运行。*但是args是有文档记录的;您只需再上一层,到^{}

args

The tuple of arguments given to the exception constructor. Some built-in exceptions (like IOError) expect a certain number of arguments and assign a special meaning to the elements of this tuple, while others are usually called only with a single string giving an error message.

因此,在ValueError中找不到其他属性的原因是没有其他属性可供查找。其他课程也一样。少数具有特殊属性的类型(OSErrorSyntaxError,可能是stdlib中其他地方的一些特定于模块的类型)显式地记录了它们。**

If we are using the except some_exception as e syntax, is doing a print e sufficient to get the exception printed out without calling its attributes

只要打印出一些有用的异常形式就足够了。同样,从BaseException文档:

If str() or unicode() is called on an instance of this class, the representation of the argument(s) to the instance are returned or the empty string when there were no arguments.

在某些情况下,这不是你想要的。特别注意,它不包括异常的类型。您可以使用repr来获得它,它提供了类似于构造函数调用的内容(例如,ValueError("invalid literal for int() with base 10: 'f'"))。在

如果您希望在回溯中得到相同的输出,您必须自己将typestr或{}放在一起,例如'{}: {}'.format(type(e), e)。在

如果你想从异常中得到实际的信息,比如基10或者字符串'f'-那么,你不能,***因为这些信息已经被丢弃了。您必须编写自己的代码来跟踪它,例如:

try:
    i = int(s, 16)
except ValueError as e:
    print '{} is not a base-16 number'.format(s)

就好像BaseException.__init__(self, *args)被定义来做self.args = tuple(args); self.message = str(args[0]) if args else ''

**我相信在2.5中,有一些异常类型具有未记录的属性,作为CPython的实现细节,但是到了2.7版本,它们要么消失了,要么被记录下来。

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

使用一个空的except很少是一个好主意,但这是一个非常罕见的情况,主要是因为您有一个备份,如果出于任何原因,您无法导入系统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

注意,现在只需要一个except子句。在

处理向用户获取这些信息的更好方法可能是先打印出来,然后使用logging模块创建一个永久记录:

^{pr2}$

然后在except子句中添加:

    logger.exception('unable to import sge')

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

相关问题 更多 >