0

私はパラメータの適切な数の任意の呼び出し可能f()を呼び出すために、次のコードを使用します。f()は、2つのパラメータの関数であるならば、ただ一つのパラメータでそれを呼び出すとTypeErrorを発生させ、その機能を適切に呼び出すことができます現在のスコープで例外が発生したかどうかをチェックする方法は?

try: 
    res = f(arg1) 
except TypeError: 
    res = f(arg1, arg2) 

exceptブランチにあります。

f()一パラメータ関数であり、例外は、例えば、(おそらくいくつかの機能に悪い呼の)f()の体内にraisenされたときに問題がある:

def f(arg): 
    map(arg) # raises TypeError 

制御フローが進みますf()の内部エラーのためにexceptブランチに転送します。もちろん、f()を2つの引数で呼び出すと、新しいTypeErrorが生成されます。その後、元のエラーへのトレースバックの代わりに、私はf()の呼び出しに2つのパラメータを使用してトレースバックを取得します。これは、デバッグ時にはあまり役に立ちません。

私のコードでは、現在の範囲で例外を発生させて例外を認識して、それを再認識することはできますか?

私はこのようなコードを書きたい:

try: 
    res = f(arg1) 
except TypeError: 
    if exceptionRaisedNotInTheTryBlockScope(): # <-- subject of the question 
     raise 
    res = f(arg1, arg2) 

私はexceptブロックでexc_info = sys.exc_info()を追加することでwalkarroundを使用することができます知っています。

f()は私のモジュールのユーザーから与えられているため、私は制御できません。また、その__name__属性は'f'以外でもかまいません。 f()への不正な再発呼によって内部例外が発生する可能性があります。 ウォークアラウンドは、作者f()によるデバッグを複雑にするので不適切です。

+0

あなたはあなたの 'except'ブロックの終わりを単に' raise'するだけです。トレースバックは、エラーが発生した場所からコールスタックをアンラップし、発生したレベルと場所を正確に示します。トレースバックを見るには、exceptinをキャッチしないか、print_exc()のようなトレースバック関数を使用しないでください。 – Muposat

+0

@Muposat reraisingは私が求めているものではありません。例外が現在のスコープ内で発生したのか、より深いところで発生したのかに応じて、条件付きで再評価する必要があります。 – abukaj

+0

後で 'e:saved_e = e'のようなTypeErrorのためにそれを保存することができ、後であなたがチェックすることができます:' saved_e:raise saved_e' – Muposat

答えて

0

は、最後にそれを考え出し:

def exceptionRaisedNotInTheTryBlockScope(): 
    return sys.exc_info()[2].tb_next is not None 

を3要素tupleを返しsys.exc_info()。最後の要素は最後の例外のトレースバックです。トレースバック・オブジェクトがトレースバック・チェーン内の唯一のものである場合、ブロックはtryブロック(https://docs.python.org/2/reference/datamodel.html)の範囲内で例外が発生しています。

https://docs.python.org/2/library/sys.html#sys.exc_infoによれば、トレースバック値を格納することは避けてください。

0

例外オブジェクトをキャプチャして調べることができます。

率直
try: 
    res = f(arg1) 
except TypeError as e: 
    if "f() missing 1 required positional argument" in e.args[0]: 
     res = f(arg1, arg2) 
    else: 
     raise 

、しかし、エラーがF内発祥場合は、元のトレースバックと二トレースバックの両方を取得する必要があるとして、例外が正常に動作する必要分類するための余分な長さを行っていない() - デバッグはすべきではありません問題。あなたはFを管理している場合

また、()あなたは2番目の引数は省略可能にし、それを第二推測することはできません。

def f(a, b=None): 
    pass 

は今、あなたはいずれかの方法で呼び出すことができます。

これはどう:

import inspect 

if len(inspect.getargspec(f).args) == 1: 
    res = f(arg1) 
else: 
    res = f(arg1, arg2) 
+0

ありがとうございます。しかし、2つの問題があります。私のモジュールのユーザが 'f()'を制御することはできません。 2番目の問題は、ほとんどの場合 'f .__ name__'(エラーメッセージで使用される)が' 'f ''と異なることです。さらに、内部の悪質な呼び出しは、 'f()'への再帰的な呼び出しであり、メッセージ分析は役に立たない...トレースバックキャプチャを使ったトリックは私のためにうまくいくが、ユーザにとって混乱を招く。 – abukaj

関連する問題