4

最近、単純だが厄介なバグに遭遇しました。私はリストを持っていて、その中で最小のメンバーを見つけたいと思っていました。Python の組み込みの min() を使用しました。いくつかの奇妙なシナリオでリストが空になるまで、すべてがうまく機能しました(私が予想できなかった奇妙なユーザー入力のために)。アプリケーションが ValueError でクラッシュしました (ところで、公式ドキュメントには記載されていません)。

私は非常に広範な単体テストを行っており、このような驚きを避けるために定期的にカバレッジをチェックしています。私も Pylint (すべて PyDev に統合されています) を使用しており、警告を無視することはありませんが、ユーザーよりも先にこのバグをキャッチできませんでした。

この種の実行時エラーを回避するために、方法論を変更できるものはありますか? (Java / C# でコンパイル時にキャッチされたものはどれですか?)。

コードを大きな try-except でラップする以上のものを探しています。他に何ができますか?このような厄介な驚きを隠しているPython関数のビルドは、他にいくつありますか???

4

4 に答える 4

7

ここでの問題は、不正な外部入力によってプログラムがクラッシュしたことです。解決策は、コードの境界で考えられる入力シナリオを徹底的に単体テストすることです。単体テストは「広範囲」であると言いますが、明らかにこの可能性をテストしていませんでした。コード カバレッジは便利なツールですが、コードをカバーすることはコードを徹底的にテストすることと同じではないことを覚えておくことが重要です。徹底的なテストとは、カバーする使用シナリオとコード行の組み合わせです。

私が使用する方法論は、内部の呼び出し元を信頼することですが、外部の呼び出し元や入力を決して信頼しないことです。したがって、外部入力を受け取る最初の関数以外のコードでは、空のリストの場合の単体テストを明示的に行いません。しかし、その入力機能は徹底的にカバーする必要があります。

この場合、ライブラリの例外は合理的な動作だと思いますmin。空のリストを要求しても意味がありません。たとえば、負の数を扱っている可能性があるため、ライブラリは合法的に 0 などの値を設定できません。

空のリストは、を要求するコードに到達するべきではなかったと思いますmin-入力時に識別され、そこで例外を発生させるか、それが機能する場合は0に設定するか、それ以外に機能するものは何でもあなたのために。

于 2010-04-15T18:50:37.910 に答える
4

Java/C# でさえ、例外のクラスである RuntimeError はチェックされず、コンパイラによって検出されません (そのため、それらは CompileError ではなく RuntimeError と呼ばれます)。

Python では、KeyboardInterrupt などの特定の例外は、プログラム内の任意の時点で事実上発生する可能性があるため、特に厄介です。

コードを大きな try-except でラップする以上のものを探しています。

それ以外はどうぞ。エラーを静かに通過させるよりも、例外をユーザーに渡してプログラムを停止させる方がはるかに優れています (Zen of Python)。

Java とは異なり、Python ではすべての例外をキャッチする必要はありません。これは、すべての例外をキャッチする必要があると、プログラマーが (空の例外ハンドラーを記述して) 例外を簡単に無視できるようになるためです。

リラックスして、エラーを停止させてください。ユーザーに報告してもらい、修正できるようにします。もう 1 つの方法は、空の必須例外ハンドラーが原因で顧客のデータがいたるところで破損しているため、42 時間デバッガーにステップインすることです。

したがって、方法論を変更する必要があるのは、例外が悪いと考えることです。それらはきれいではありませんが、代替品よりも優れています。

于 2010-04-15T18:26:39.103 に答える
1

無作為化テストを使用することもできました。

#!/usr/bin/env python
import random
from peckcheck import TestCase, an_int, main

def a_seq(generator):
    return lambda size: [generator(size) 
                         for _ in xrange(random.randrange(size))] 

class TestMin(TestCase):
    def testInputNoThrow(self, x=a_seq(an_int)):
        min(x)

if __name__=="__main__":
    main()

をインストールするには、次のようpeckcheckに入力します。

$ pip install http://github.com/downloads/zed/peckcheck/peckcheck-0.1.v2.6.tar.gz

または単にグラブpeckcheck.py

于 2010-04-15T21:07:19.247 に答える
0

あなたの質問に対する直接的な答えはわかりません。pylint がそのような可能性について警告してくれたら、私も大好きです。空のリストがあらゆる種類の状況で問題を引き起こすことを考えると、私の一般的な慣行は、それらを使用する前にリストが真実かどうかをチェックすることです。例えば:

val = min(vals) if vals else 0

とにかくチェックする必要があることが多いため、多くの場合、これは「無料」Noneです。また、ゼロ項目を処理するために新しいスレッド、プロセス、またはデータベース トランザクションを開始することを回避するために、特別なケースの空のリストにパフォーマンスの観点から報いることもできます。

于 2010-04-15T18:41:09.513 に答える