2016-04-05 14 views
0

値がstr型かどうかを確認するアサーションを持つプロパティがあります。Pythonのデコレータのプロパティで例外を処理する

このアサーションをキャッチするにはエラー私はオンラインで見つかった例に従ってデコレータを作成しました。

デコレータ:

def catch_assertionerror(function): 
    def handle_problems(*args, **kwargs): 
     try: 
      return function(*args, **kwargs) 
     except AssertionError: 
      # log_error(err.args[0]) 
      print "error caught" 
    return handle_problems 

プロパティ:

nameプロパティを設定する
@catch_assertionerror 
@name.setter 
def name(self, value): 
    assert isinstance(value, str), "This value should be a string" 
    self._name = name 

self.name = self.parse_name_from_xml() 

私はこのコードを実行すると、そこにはエラー示すがありませんので、私はそれを推測一方、エラーメッセージは画面に表示されません。

は、それから私は私がStachoverflowで見つけもっと簡単な例を試してみました:

def handleError(function): 
    def handleProblems(): 
     try: 
      function() 
     except Exception: 
      print "Oh noes" 
    return handleProblems 


@handleError 
def example(): 
    raise Exception("Boom!") 

これは、エラーを処理しますが、画面にエラーメッセージをプリントしませんでした。

誰かが私にここで行方不明を説明することができますか?

+1

関数を呼び出す場所にコードが表示されていません – hspandher

+0

私はインタラクティブなPythonセッションで "もっと簡単な例"を試したところ、期待どおりに動作しています。どのようにこのコードを実行していますか? – SpoonMeiser

答えて

4

あなた後者の例では、私のために動作しますが、あなたの主な問題は、あなたが

@catch_assertionerror 
@name.setter 
def name(self, value): 
    assert isinstance(value, str), "This value should be a string" 
    self._name = name 

が、descriptorcatch_assertionerrorで関数をラップしていないことです。さらに悪いことに、関数を返すのではなく、元の記述子をラップする新しい記述子ではありません。今度はname属性に代入すると、ラッパー関数を割り当てられた値に置き換えるだけです。ステップバイ

ステップ、元のクラス定義を使用して:

class X(object): 

    @property 
    def name(self): 
     return self._name 

    @catch_assertionerror 
    @name.setter 
    def name(self, value): 
     assert isinstance(value, str), "This value should be a string" 
     self._name = value 

>>> x = X() 
>>> x.name 
<unbound method X.handle_problems> 
>>> x.__dict__ 
{} 
>>> x.name = 2 
>>> x.name 
2 
>>> x.__dict__ 
{'name': 2} 

何をしなければならないことは代わりにメソッドの機能をラップして、記述子取扱デコレータに渡しです:

class X(object): 
    @property 
    def name(self): 
     return self._name 
    @name.setter 
    @catch_assertionerror 
    def name(self, value): 
     assert isinstance(value, str), "This value should be a string" 
     self._name = value 

ので、 :

>>> x = X() 
>>> x.name 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "<stdin>", line 4, in name 
AttributeError: 'X' object has no attribute '_name' 
>>> x.name = 2 
error caught 
>>> x.name = "asdf" 
>>> x.name 
'asdf' 

今後はfunctools.wrapsfunctools.update_wrapperを使用することを検討してください。あなたのラッパーが非表示になりますので、それらがなければ、あなたのクラスと関数は、検査することが困難です元:

>>> @catch_assertionerror 
... def this_name_should_show(): pass 
... 
>>> this_name_should_show 
<function handle_problems at 0x7fd3d69e22a8> 

あなたのデコレータこの方法の定義:

>>> @catch_assertionerror 
... def this_name_should_show(): pass 
... 
>>> this_name_should_show 
<function this_name_should_show at 0x7fd3d69e21b8> 

def catch_assertionerror(function): 
    @wraps(function) 
    def handle_problems(*args, **kwargs): 
     ... 
    return handle_problems 

は、元の関数の情報を保持しますが

問題があることをあなたにも示しています。

# When trying to define the class 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "<stdin>", line 6, in X 
    File "<stdin>", line 2, in catch_assertionerror 
    File "/usr/lib/python2.7/functools.py", line 33, in update_wrapper 
    setattr(wrapper, attr, getattr(wrapped, attr)) 
AttributeError: 'property' object has no attribute '__module__'