S.Lott の回答が最適です。しかし、これは彼のコメントに追加するには長すぎるので、ここに入れました. とにかく、それは私が assert についてどのように考えているかということです。
とにかく、入力チェックには 2 つの考え方があります。ターゲットで実行することも、ソースで実行することもできます。
ターゲットでそれを行うことは、コード内にあります。
def sqrt(x):
if x<0:
raise ValueError, 'sqrt requires positive numbers'
root = <do stuff>
return root
def some_func(x):
y = float(raw_input('Type a number:'))
try:
print 'Square root is %f'%sqrt(y)
except ValueError:
# User did not type valid input
print '%f must be a positive number!'%y
さて、これには多くの利点があります。おそらく、sqrt を書いた人は、自分のアルゴリズムの有効な値について最もよく知っています。上記では、ユーザーから取得した値が有効かどうかわかりません。誰かがそれをチェックする必要があり、何が有効かを最もよく知っているコード、つまり sqrt アルゴリズム自体でそれを行うのは理にかなっています。
ただし、パフォーマンスが低下します。次のようなコードを想像してください。
def sqrt(x):
if x<=0:
raise ValueError, 'sqrt requires positive numbers'
root = <do stuff>
return root
def some_func(maxx=100000):
all_sqrts = [sqrt(x) for x in range(maxx)]
i = sqrt(-1.0)
return(all_sqrts)
さて、この関数は sqrt を 100k 回呼び出します。そして毎回、sqrt は値が >= 0 であるかどうかを確認します。しかし、これらの数値を生成する方法により、それが有効であることは既にわかっています。これらの余分な有効なチェックは、実行時間を浪費するだけです。それらを取り除くのはいいことではありませんか?そして、ValueError をスローするものがあるので、それをキャッチして、間違いを犯したことに気付きます。私はサブ関数に依存してチェックするプログラムを書いているので、それがうまくいかないときの回復を心配するだけです。
2 番目の考え方は、ターゲット関数が入力をチェックする代わりに、定義に制約を追加し、呼び出し元が有効なデータで呼び出していることを確認する必要があるというものです。この関数は、適切なデータがあれば、そのコントラクトが示す内容を返すことを約束します。これにより、これらのチェックがすべて回避されます。呼び出し元は、送信元の関数よりも、送信しているデータ、データの送信元、固有の制約について多くのことを知っているためです。これらの最終結果は、コード コントラクトと同様の構造ですが、もともとこれは慣習によるものでした。つまり、以下のコメントのように設計されていました。
# This function valid if x > 0
def sqrt(x):
root = <do stuff>
return root
def long_function(maxx=100000):
# This is a valid function call - every x i pass to sqrt is valid
sqrtlist1 = [sqrt(x) for x in range(maxx)]
# This one is a program error - calling function with incorrect arguments
# But one that can't be statically determined
# It will throw an exception somewhere in the sqrt code above
i = sqrt(-1.0)
もちろん、バグが発生し、契約違反が発生する可能性があります。しかし、これまでのところ、結果はほぼ同じです。どちらの場合も、sqrt(-1.0) を呼び出すと、sqrt コード自体の内部で例外が発生し、例外スタックを調べて、バグがどこにあるかを突き止めることができます。
ただし、もっと陰湿なケースがあります...たとえば、私のコードがリスト インデックスを生成し、それを格納し、後でリスト インデックスを検索し、値を抽出し、何らかの処理を行うとします。そして、たまたま -1 のリスト インデックスを取得したとしましょう。これらのすべてのステップは実際にはエラーなしで完了する可能性がありますが、テストの最後に間違ったデータがあり、その理由はわかりません。
では、なぜ主張するのでしょうか。コントラクトをテストおよび証明している間に、障害に近いデバッグ情報を取得できるものがあると便利です。これは最初の形式とほぼ同じです。結局のところ、まったく同じ比較を行っていますが、構文的にはより簡潔で、コントラクトの検証に少し特化しています。副次的な利点は、プログラムが機能することを合理的に確信し、最適化して、より高いパフォーマンスとデバッグ可能性を探している場合、これらの冗長なチェックをすべて削除できることです。