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

これは、特定の ORM 関連の例外に対して Django が使用する正確なパターンです。

利点は、インスタンスを介してアクセスされる型に対してチェックする 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()

rickDjango の例外は通常、すべてグローバル基底クラスから派生するため、不明な (または提供されていない) クラスの場合に備えて、例外の種類をオンにする catch-all 句を使用することもできます。

これがそれほど一般的ではない理由は、(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 を使用する主な理由 (ポリモーフィズム) の 1 つは、多少妥協しています。しかし、必ずしもそれを使用できない、または使用すべきではないという意味ではありません。制限に注意してください。

これで最初の不可解な予約がクリアされたことを願っています。

于 2012-11-13T20:23:14.130 に答える