在Python中如何正确定义异常类层次结构?

2 投票
1 回答
1347 浏览
提问于 2025-04-17 21:23

我想要能够像内置异常那样抛出异常,你可以选择传递一条消息,或者直接抛出类名(实例会自动创建)。像这样:

raise IndexError

raise IndexError('Something went wrong, bro')

我的代码这样写对吗?

最开始我想的是这样:

class SomeError(Exception):
    def __init__(self, *args):
        if args:
            print ' '.join(args)

class SomeCriticalError(SomeError):
    def __init__(self, *args):
        super(SomeCriticalError,self).__init__(*args)
        print 'This is a critical error, process stopped ...'
        sys.exit(1)

class SomeCookiesError(SomeCriticalError):
    def __init__(self, *args):
        print 'Firefox cookies retrieving failed ..'   
        super(SomeCookiesError,self).__init__(*args)

但在这种情况下,我必须为每个CmiCriticalError的子类定义__init__(),我觉得这样不太对(在每个子类中调用super()感觉很别扭),然后我试了这个:

class SomeError(Exception):
    def __init__(self, *args):
        if args:
            print ' '.join(args)
        else:
            print self

class SomeCriticalError(SomeError):
    def __init__(self, *args):
        super(SomeCriticalError,self).__init__(*args)
        print 'This is a critical error, process stopped ...'
        sys.exit(1)

class SomeCookiesError(SomeCriticalError):
    def __str__(self):
        return 'Firefox cookies retrieving failed ..'

但这仍然让我觉得不太对劲,我漏掉了什么吗?

其实我想做的是在异常实例内部处理异常,就像SomeCriticalError中的sys.exit()那样,因为在我的主代码中,我可能会在多个地方抛出SomeCookiesError,我不想每次都传递相同的消息字符串参数,所以我能不能像内置异常那样做?(当没有传递参数时,打印默认消息)

1 个回答

1

一般来说,一个Exception(异常)子类并不负责处理导致它被抛出的错误。这部分工作是由错误处理代码来完成的,比如用try/catch语句包裹住抛出异常的地方。异常类型应该主要负责提供一个友好的提示信息,并封装一些相关的数据。

所以,在你的例子中,处理“严重”错误的方法就是不去捕捉它们(或者只在最顶层捕捉,之后再退出程序)。很多异常类可以很简单:

class SomeCriticalError(Exception):
    pass

一些其他的异常类可能会做得多一些,但它们应该专注于记录情况的相关细节,而不是解决问题的方法:

class CookieError(Exception):
    def __init__(self, cookie_name):
        super(CookiesError, self).__init__("Could not find Firefox cookie {!r}"
                                           .format(cookie_name)) # custom message

如果你在调试CookieError时需要一些额外的数据,你可以让你的异常类把这些数据保存到self.data或者其他地方(不过如果你想让raise CookieError的语法正常工作,你需要把__init__方法的所有参数设为可选)。

撰写回答