3

いくつかのテストケースがあります。テストケースは、計算に時間がかかるデータに依存しています。テストを高速化するために、データをキャッシュして、再計算する必要がないようにしました。

foo()キャッシュされたデータを調べるがあります。テストケースに大きく依存するため、何が表示されるかを事前に知ることはできません。

テストケースが失敗した場合、適切なキャッシュデータが見つからないため、失敗したくありません。データを計算してから再試行します。また、特にどの例外がデータの欠落の原因となるのかもわかりません。

私のコードは今次のようになっています:

if cacheExists:
    loadCache()
    dataComputed = False
else:
    calculateData()
    dataComputed = True

try:
    foo()
except:
    if not dataComputed:
        calculateData() 
        dataComputed = True
        try:
            foo()
        except:
            #error handling code
    else:
        #the same error handling code

このコードを再構築するための最良の方法は何ですか?

4

5 に答える 5

4

私は既存の回答の重要な提案に同意しません。これは基本的に、たとえばC++やJavaの場合と同じようにPythonで例外を処理することになります。これはPythonでは推奨されないスタイルです。許可よりも許しを求める」(コードのメインフローを覆い隠し、徹底的な予備チェックによってオーバーヘッドを発生させるのではなく、操作を試み、例外がある場合はそれに対処します)。私はガブリエルに同意します。ベアexceptは決して良い考えではありません(raise例外を伝播させるために何らかの形式のロギングとそれに続くaが続く場合を除きます)。したがって、期待するすべての例外タイプを備えたタプルがあり、同じ方法で処理したいとします。

expected_exceptions = KeyError, AttributeError, TypeError

except expected_exceptions:裸ではなく常に使用しますexcept:

したがって、それが邪魔にならないように、ニーズに対する繰り返しの少ないアプローチの1つは次のとおりです。

try:
    foo1()
except expected_exceptions:
    try:
        if condition:
            foobetter()
        else:
            raise
    except expected_exceptions:
        handleError()

別のアプローチは、補助関数を使用してtry/exceptロジックをラップすることです。

def may_raise(expected_exceptions, somefunction, *a, **k):
  try:
    return False, somefunction(*a, **k)
  except expected_exceptions:
    return True, None

このようなヘルパーは、いくつかの異なる状況で役立つことが多いため、プロジェクトの「ユーティリティ」モジュールのどこかにこのようなものがあるのはかなり一般的です。さて、あなたのケース(引数なし、結果なし)では、以下を使用できます:

failed, _ = may_raise(expected_exceptions, foo1)
if failed and condition:
  failed, _ = may_raise(expected_exceptions, foobetter)
if failed:
  handleError()

私が主張するのは、より直線的であり、したがってより単純です。この一般的なアプローチの唯一の問題は、などの補助関数may_raiseが何らかの方法で例外を処理することを強制しないため、そうすることを忘れる可能性があることです(例外の代わりにリターンコードを使用するのと同じように、エラーを示し、それらの戻り値が誤って無視される傾向があります); だから、控えめに使ってください...!-)

于 2009-08-27T21:26:26.757 に答える
1

包括的例外を使用することは、通常、良い考えではありません。そこでどのような例外を期待していますか?KeyError、AttributeError、TypeError ...

探しているエラーの種類を特定したら、例外を処理する前にhasattr()in演算子やその他の条件をテストするものを使用できます。

そうすれば、ロジックフローをクリーンアップして、実際に壊れているものの例外処理を保存できます。

于 2009-08-27T20:29:44.733 に答える
1

フローを表現する良い方法がない場合もあります。それは単に複雑です。ただし、foo()を1つの場所でのみ呼び出し、エラー処理を1つの場所でのみ行う方法は次のとおりです。

if cacheExists:
    loadCache()
    dataComputed = False
else:
    calculateData()
    dataComputed = True

while True:
    try:
        foo()
        break
    except:
        if not dataComputed:
            calculateData()
            dataComputed = True
            continue 
        else:
            #the error handling code
            break

あなたはループ、YMMVが好きではないかもしれません...

または:

if cacheExists:
    loadCache()
    dataComputed = False
else:
    calculateData()
    dataComputed = True

done = False
while !done:
    try:
        foo()
        done = True
    except:
        if not dataComputed:
            calculateData()
            dataComputed = True
            continue 
        else:
            #the error handling code
            done = True
于 2009-08-28T01:00:47.687 に答える
1

AlexMartelliが提案した代替アプローチが好きです。

may_raiseの引数として関数のリストを使用することについてどう思いますか。関数は1つが成功するまで実行されます!

これがコードです

def foo(x):
    Exception( "Arrrgh!")を発生させます
    0を返す

def foobetter(x):
    「こんにちは」を印刷、x
    リターン1

def try_many(functions、expected_exceptions、* a、** k):
    ret=なし
    関数のfの場合:
        試す:
            ret = f(* a、** k)
        expected_exceptionsを除いて、e:
            eを印刷する
        そうしないと:
            壊す
    retを返す

print try_many((foo、foobetter)、Exception、 "World")

結果は

ああ!
こんにちは世界
1
于 2009-08-28T12:40:01.260 に答える
0

呼び出しを行う前にfoobetter()を実行するかどうかを判断する方法はありますか?例外が発生した場合は、予期しない(例外的な!)何かが発生したことが原因である必要があります。フロー制御に例外を使用しないでください。

于 2009-08-27T20:25:24.397 に答える