使用添加的上下文信息在Python 2.x中重新引发异常

时间:2013-06-07 16:56:27

标签: python exception exception-handling python-2.x

C#background

我来自一个C#上下文,您可以在其中捕获异常并抛出一个新异常,包括原始异常作为内部异常。这样你可以得到这样的东西:

void LoadPlugin(string configFile)
{
    try
    {
        OpenAndReadConfig(configFile);
        DoMoreStuff();
    }
    catch (Exception ex)
    {
        throw new PluginException("Could not load plugin", ex);
    }
}

void OpenAndReadConfig(string configFile)
{
    try
    {
        OpenFile(configFile); // file does not exist
        DoStuff();
    }
    catch (Exception ex)
    {
        throw new ConfigurationException("Error reading configuration", ex);
    }
}

因此,如果某些代码调用LoadPlugin(@"non\existing\file.xml"),您将拥有以下异常链,每个异常都会保留自己的堆栈跟踪:

  • PluginException:无法加载插件
    • ConfigurationException:读取配置时出错
      • FileNotFoundException:找不到文件'C:\ non \ existing \ file.xml'

Python问题

现在我正在使用Python 2.6上的一些库代码,我想实现类似的东西。在查看了几个SO问题和博客/论坛后,我想出了一个对我来说足够好的解决方案,但由于我对Python的经验有限,我不知道是否有一些我不知道的警告。我的想法是做这样的事情:

def open_and_read_config(config_file):
    try:
        open_file(config_file) # file does not exist
        do_stuff()
    except Exception, ex:
        ex.args = ('Error reading configuration',) + ex.args
        raise

def load_plugin(config_file):
    try:
        open_and_read_config(config_file)
        do_more_stuff()
    except Exception, ex:
        ex.args = ('Could not load plugin',) + ex.args
        raise

这样我就可以保留原始异常的消息和回溯,同时能够添加上下文信息。我可以看到的一个缺点是,这只允许我在消息字符串的形式上添加上下文信息,而不是新的异常类型(例如ConfigurationErrorPluginError)。此外,仅对原始(最内层)异常保留回溯。

那么,还有什么我想念的吗?你有什么理由建议不要使用这种方法吗?

1 个答案:

答案 0 :(得分:0)

在python中,您只有一个回溯 - 用于最后创建的异常。如果要拆分回溯,则应在except子句和raise新异常中获取当前回溯,并使用此跟踪和嵌套异常的适当类型,即:

import traceback
class TracebackableException(Exception):
    def __init__(self, message, traceback, inner=None):
        self.message = message
        self.traceback = traceback
        self.inner = inner

class ConfigurationException(TracebackableException): pass
class PluginException(TracebackableException): pass

...

def open_and_read_config(config_file):
    try:
        open_file(config_file) # file does not exist
        do_stuff()
    except IOError, ex:
        raise ConfigurationException("Cannot load config", traceback.format_exc(), ex)

def load_plugin(config_file):
    try:
        open_and_read_config(config_file)
        do_more_stuff()
    except Exception, ex:
        raise PluginException("Cannot load plugin", traceback.format_exc(), ex)