7

我发现自己经常想像这样构建我的异常类:

# legends.py
class Error(Exception): pass

class Rick(object):
    class Error(Error): pass
    class GaveYouUp(Error): pass
    class LetYouDown(Error): pass

class Michael(object):
    class Error(Error): pass
    class BlamedItOnTheSunshine(Error): pass
    class BlamedItOnTheMoonlight(Error): pass

我只在 Django ( DoesNotExist) 中看到过这种模式,它非常有意义。有什么我遗漏的吗,为什么大多数人似乎都喜欢顶级例外?

编辑 我会将这些类用于通用粒度,例如:

import legends

try:
    do_stuff()
except legends.Michael.Error:
    blame_it_on_the_boogie()
except legends.Rick.GaveYouUp:
    let_you_down()
except legends.Error:
    pass
except Exception as e:
    raise Hell()
4

2 回答 2

9

这是 Django 用于某些 ORM 相关异常的确切模式。

优点是您可以有一个 except 子句来检查通过实例访问的类型:

rick = Rick()

try:
   rick.roll()
except rick.GaveYouUp:
   never()
except rick.LetYouDown:
   never_ever()

这在这里看起来没什么用,但如果rick是函数参数,那么它可能会相当有用。

这在编写引发异常的通用代码时也非常有用:

GoddamStar(object):
   def sing(self,tune):
       raise self.Error()

class Rick(GoddamStar):
    class Error(Error): pass
    class GaveYouUp(Error): pass
    class LetYouDown(Error): pass

class Michael(GoddamStar):
    class Error(Error): pass
    class BlamedItOnTheSunshine(Error): pass
    class BlamedItOnTheMoonlight(Error): pass

rick = Rick()

try:
   rick.sing()
except Rick.GaveYouUp:
   never()
except Michael.Error:
   never_ever()

Django 的异常通常都派生自全局基类,因此您还可以有一个包罗万象的子句,它仍然会打开一种异常类型,以防您rick属于未知(或未提供的)类。

这并不常见的原因是(a)它不适用于早期绑定的语言,这吸引了大多数书籍作者(b)这对用户有用的情况很少见,因此应用程序作家可能认为他们不需要它。

于 2012-11-13T20:25:01.573 回答
1

如果你想在 Micheal 之外引发例如 BlamedItOnTheSunshine,你必须通过 raise Micheal.BlamedItOnTheSunshine('error text') 来调用它。

例如:

class A:
    class E(Exception): pass
    def __init__(self): raise A('error in A')

class B:
    def __init__(self): raise A.E('error in B')

在此示例中,A 和 B 不相关,但如果您有如下关系:

class Interpret(object):
    class LetsYouDown(Exception): pass
    def __init__(self): raise self.LetsYouDown("I'm not Rick!")

class Michael(Interpret):
    class BlameItOnTheSunshine(Exception): pass
    def __init__(self): raise self.BlameItOnTheSunshine("It's not the Moon!")

class Rick(Interpret):
    class NeverEver(Exception): pass
    def __init__(self): print "Never Ever!"

and want now something like:
    try:
        for superstar in [Interpret, Michael, Rick]:
            star_in_show = superstar()            
    except superstar.LetsYouDown:
        print "Where's Rick?"
    except superstar.BlameItOnTheSunshine:
        print "Must be Michael!"

你会得到一个错误,我称之为违反 Liskov 原则。因此,使用 OOP 的主要原因之一(多态性)在某种程度上受到了损害。但这并不一定意味着您不能或不应该使用它。请注意这些限制。

我希望这能清除我最初的隐秘保留。

于 2012-11-13T20:23:14.130 回答