27

私は通常、コードをできるだけ一般的にしたいと思っています。私は現在、単純なライブラリを作成していますが、ライブラリでさまざまなタイプを使用できることは、今回は非常に重要だと感じています。

進む方法の1つは、人々に「インターフェース」クラスをサブクラス化するように強制することです。私には、これはPythonよりもJavaのように感じissubclassられ、各メソッドで使用することもあまり魅力的ではありません。

私の好ましい方法は、オブジェクトを誠実に使用することですが、これにより、いくつかのが発生しAttributeErrorsます。それぞれの危険な呼び出しをtry/exceptブロックでラップすることができます。これもちょっと面倒なようです:

def foo(obj):
    ...
    # it should be able to sleep
    try:
        obj.sleep()
    except AttributeError:
        # handle error
    ...
    # it should be able to wag it's tail
    try:
        obj.wag_tail()
    except AttributeError:
        # handle this error as well

エラー処理をスキップして、必要なメソッドを持つオブジェクトのみを使用することを期待する必要がありますか?[x**2 for x in 1234]私が実際にaを取得し、aを取得しTypeErrorないような愚かなことをした場合AttributeError(intは反復可能ではありません)、どこかでタイプチェックが行われている必要があります-同じことをしたい場合はどうなりますか?

この質問は一種の自由形式になりますが、上記の問題をクリーンな方法で処理するための最良の方法は何ですか?確立されたベストプラクティスはありますか?たとえば、上記の反復可能な「タイプチェック」はどのように実装されますか?

編集

AttributeErrorsは問題ありませんが、ネイティブTypeErrors関数によって生成されるものは、通常、エラーを解決する方法に関する詳細情報を提供します。これを例に取ってください:

>>> ['a', 1].sort()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unorderable types: int() < str()

私の図書館ができるだけ役立つようにしたいと思います。

4

5 に答える 5

18

私はPythonのプロではありませんが、パラメーターが特定のメソッドを実装していない場合の代替手段を試すことができない限り、例外がスローされるのを防ぐべきではないと思います. 呼び出し元がこれらの例外を処理できるようにします。このようにして、開発者から問題を隠すことができます。

Clean Codeで読んだように、コレクション内のアイテムを検索する場合ìssubclassは、(リストの) でパラメーターをテストせず、を呼び出すことを好みますgetattr(l, "__contains__")。これにより、コードを使用している誰かが、リストではないがメソッドが定義されているパラメーターを渡す機会が与えられ__contains__、物事は同様にうまく機能するはずです。

したがって、できるだけ制限を少なくして、抽象的一般的な方法でコーディングする必要があると思います。そのためには、仮定をできるだけ少なくする必要があります。ただし、処理できない問題に直面した場合は、例外を発生させて、プログラマーに彼が犯した間違いを知らせてください!

于 2011-07-05T23:41:39.260 に答える
12

コードに特定のインターフェイスが必要で、ユーザーがそのインターフェイスなしでオブジェクトを渡す場合、10 分の 9 の確率で例外をキャッチするのは不適切です。ほとんどのAttributeError場合、これは合理的であるだけでなく、インターフェイスの不一致に関しては予想されます。

AttributeError場合によっては、次の 2 つの理由のいずれかでをキャッチすることが適切な場合があります。インターフェイスの一部の側面をオプションにするか、より具体的な例外 (おそらくパッケージ固有の例外サブクラス) をスローする必要があります。エラーとその後の結果を正直に処理していない場合は、例外がスローされるのを防ぐべきではありません。

したがって、この質問に対する答えは、問題とドメインに固有のものでなければならないように思えます。これは基本的に、Cowオブジェクトの代わりにオブジェクトを使用することが機能するかどうかの問題ですDuck。もしそうなら、あなたが必要なインターフェースの混乱を処理すれば、それで問題ありません。一方、誰かがあなたにFrogオブジェクトを渡したかどうかを明示的にチェックする理由はありません。それが悲惨な失敗 (つまり、スタック トレースよりもはるかに悪いこと) を引き起こさない限りです。

とは言っても、インターフェースを文書化することは常に良い考えです。これが、(とりわけ) docstrings の目的です。考えてみると、ユーザーが発生する可能性のあるすべてのエラーを予測してカスタム エラー メッセージを作成するよりも、ほとんどの場合に一般的なエラーをスローし、docstring で正しい方法をユーザーに伝える方がはるかに効率的です。

最後の警告 -ここでUIについて考えている可能性があります - それは別の話だと思います。エンド ユーザーが提供する入力をチェックして、それが悪意のあるものでもひどく不正なものでもないことを確認し、スタック トレースの代わりに有用なフィードバックを提供することをお勧めします。しかし、ライブラリやそのようなものについては、コードを使用しているプログラマーがコードを知的かつ敬意を持って使用し、Python が生成するエラーを理解していることを本当に信頼する必要があります。

于 2011-07-06T00:16:10.267 に答える
7

実装されていないメソッドに何もさせたくない場合は、複数行のtry/except構造ではなく、次のようなものを試すことができます。

getattr(obj, "sleep", lambda: None)()

ただし、これは関数呼び出しとして必ずしも明白ではないため、次のようになります。

hasattr(obj, "sleep") and obj.sleep()

または、実際に呼び出すことができる何かを呼び出す前に、もう少し確実にしたい場合:

hasattr(obj, "sleep") and callable(obj.sleep) and obj.sleep()

この「飛び出す前に見る」パターンは、一般に Python で行うのに推奨される方法ではありませんが、完全に読みやすく、1 行に収まります。

もちろん、別のオプションはtry/except、を別の関数に抽象化することです。

于 2011-07-05T23:44:03.913 に答える
6

良い質問で、非常に自由回答です。典型的な Python スタイルは、isinstance を使用するか、個々の例外をキャッチするかのいずれかで、チェックしないことだと思います。確かに、 isinstance の使用はダックタイピングのポイント全体を無効にするため、非常に悪いスタイルです (ただし、プリミティブで isinstance を使用することは問題ありません。整数入力の場合は int と long の両方を確認し、文字列の場合は basestring (base) を確認してください)。 str および unicode のクラス) チェックする場合は、TypeError を発生させる必要があります。

通常は TypeError または AttributeError のいずれかが発生するため、チェックしなくても問題ありません。(ただし、これらのエラーを遅らせて、クライアント コードのデバッグを困難にする可能性があります)。

TypeErrors が表示される理由は、実質的に isinstance を実行するため、プリミティブ コードがそれを発生させるためです。for ループは、何かが反復可能でない場合に TypeError を発生させるようにハードコードされています。

于 2011-07-05T23:33:36.290 に答える
3

まず第一に、あなたの質問のコードは理想的ではありません:

try:
    obj.wag_tail()
except AttributeError:
    ...

AttributeErrorのルックアップによるwag_tailものか、関数内で発生したものかはわかりません。あなたがやろうとしていることは次のとおりです。

try:
    f = getattr(obj, 'wag_tail')
except AttributeError:
    ...
finally:
    f()

f編集:kindallは、これをチェックする場合は、それが呼び出し可能であることもチェックする必要があることを正しく指摘しています。

一般に、これは Pythonic ではありません。呼び出して例外フィルターをダウンさせるだけで、スタック トレースから問題を解決するのに十分な情報が得られます。再スローされた例外が、このエラー チェック コードのすべてを正当化するのに十分役立つかどうかを自問する必要があると思います。

リストを並べ替える場合は、その好例です。

  • リストの並べ替えは非常に一般的です。
  • 順序付け不可能な型を渡すことは、それらのかなりの割合で発生します。
  • その場合に AttributeError をスローすると、非常に混乱します。

これらの 3 つの基準があなたの問題 (特に 3 つ目) に当てはまる場合、かなり例外的な再スローワーを構築することに同意します。

これらのかなりのエラーをスローすると、コードが読みにくくなるという事実とバランスをとる必要があります。これは、統計的にコード内のバグが増えることを意味します。メリットとデメリットのバランスの問題です。

__real__動作 (や など)をチェックする必要がある場合は、 、、および__contains__にある Python 抽象基本クラスを使用することを忘れないでください。collectionsionumbers

于 2011-07-06T07:24:51.753 に答える