2017-04-10 11 views
3

デコレータクラスを使用して例外を装飾しましたが、例外は正確な例外クラスでは除外できないようです。 Functools.update_wrapperを使用してデコレータクラスを更新することもできません。Pythonで装飾された例外例外が除外されない

class ClsDecor(object): 

    def __init__(self,cls): 
     self.cls=cls 
     self.counter=0 

    def __call__(self,*args): 
     self.counter+=1 
     return self.cls(*args) 

@ClsDecor 
class Err(Exception): 
    def __init__(self): 
     Exception.__init__(self) 

try: 
    raise Err() 
except Err as e: 
    print 'catched' 
except Exception as e: 
    print 'Not catched' 
+0

あなたは 'Exception'からデコレータを派生させてみましたか? –

+0

ありがとう、試して、doesnt仕事。 – Max

+2

'@ ClsDecor'の後、' Err'は 'ClsDecor'の*インスタンス*です。 'Err()'は初期の 'Err'クラスのインスタンスを返します(その名前は装飾によって上書きされます)。 'Err'と' Err() 'から返されたインスタンスの間に明らかな型の不一致があります。型は実際には 'Err.cls'です。 – dhke

答えて

0

この問題は装飾にはありません。多分装飾があなたを混乱させるかもしれませんが、それは問題ではありません。

あなたはErrが何であるかを理解する必要があります。デコレータは通常の定義のように動作しますが、オブジェクトにデコレータを適用してから名前に割り当てます。それはそれはと同等ですです:今

class Err(Exception): 
def __init__(self): 
    Exception.__init__(self) 
Err = ClsDecor(Err) 

ErrClsDecorインスタンスであり、あなたは(クラスではなく)インスタンスを呼び出していることを上げたとき、あなたはClsDecor.__call__を呼び出して(とないClsDecor.__init__)されます。 (argsself.clsに電話をかけようとしましたが、self.clsErrです。追加の引数はありません(self以外)。

デフォルトのexcept句にエラーを出力した場合は、これを見たことがあります。例外やトレースバック意志をキャッチされない場合 - そのすべてで

except Exception as e: 
    print 'Not catched', repr(e) 
    raise 

それとも、あなたがキャッチしてはならない。それはあなたが予期しない例外をキャッチするので、それはしばしばなので、デフォルトの句をヒットした場合、エラーを印刷することをお勧めしますとにかく印刷されます。すべての

+0

私はタイプ情報をデフォルトで取得しようとしましたが、それは __main__です。Err '>、混乱してしまいました。タイプErrとみなされるべきだと思っていました。 – Max

+0

@ user3011780試してみると、そうであってはいけません。あなたが考慮すべきもう一つのことは、デフォルトの 'except'節をまったく持たないことです。これは通常、あなたが期待していなかった例外があることを意味します。そして、あなたはそれをどうにか処理する方法を知らないでしょう。そして、 Pythonからの通常のスタックトレースエラーメッセージが返されます。これは、エラーが発生した場所を示します。 – skyking

+0

TypeErrorは、以前の投稿の誤字 '* args'が 'args'に起因するはずです。あなたの親切な提案に感謝します。 – Max

2

まず、方法__call__は次のようになります。

def __call__(self, *args): 
    return self.cls(*args) 

あなたのコードは__call__内部エラーが発生しますし、print 'Not catched'に直接あなたをもたらし、これは最初のレベルのエラーです。このエラーを修正すると、タイプミスマッチの2番目のレベルのエラーになります。これは、dhkeのコメントでよく説明されています。基本的な考え方は、Err@ClsDecorの後に実際にタイプClsDecorですが、生タイプErrのインスタンスを__call__に返します。これは明らかにexcept Errと一致しません。

コメントに要件のために更新さ
def err_dec(Cls): 
    class NewErr(Exception): 
     def __init__(self, *args, **kwargs): 
      self.err = Cls(*args, **kwargs) 
return NewErr 

@err_dec 
class Err(Exception): 
    def __init__(self): 
     Exception.__init__(self) 

:あなたは簡単のようなあなたの目的をアーカイブするためにデコレータを使用することができます

def err_dec(Cls): 
    class NewErr(Exception): 
     c = 0 
     def __init__(self, *args, **kwargs): 
      NewErr.c = NewErr.c + 1 
      self.err = Cls(*args, **kwargs) 
     def counter(self): 
      return NewErr.c 
    return NewErr 

@err_dec 
class Err(Exception): 
    def __init__(self): 
     Exception.__init__(self) 

try: 
    Err() 
    Err() 
    raise Err() 
except Err as e: 
    print e.counter() 
    print 'catched' 
except Exception as e: 
    print 'Not catched' 
+0

私の本来の目的は、いくつかの例外に対してカウンタデコレータを作ろうとしていたので、処理した後、この種の無視できるエラーがどれだけ発生したかのカウンタを得ることができます。 – Max

+0

あなたは私の答えの更新された部分をチェックアウトすることができます:-)それが参考になることを願っています。 – shizhz

+0

ありがとうございました。たくさんの助けになりました。最後に、新しいクラス名を変更して元の名前と一致するようにメタクラスを使用しました。^_^ – Max

0

みんなが助けてすべてのuを使用すると、最終的に私はこのような解決策を得た:

class ErrMetaClass(type): 
     def __new__(mcls,cls_name,cls_parents,cls_attr): 
      return super(ErrMetaClass,mcls).__new__(mcls, 
        cls_attr['_cls'].__name__, cls_parents,cls_attr) 

    def err_dec(cls): 
     class NewErr(Exception): 
      __metaclass__ = ErrMetaClass 
      _cls=cls 
      c=0 
      def __init__(self): 
       NewErr.c+=1 
     return NewErr 

    @err_dec 
    class Err(Exception): 
     def __init__(self): 
      Exception.__init__(self) 

    try: 
     raise Err() 
    except Err as e: 
     print Err.c 
    except Exception as e: 
     print type(e) 
関連する問題