2011-12-19 4 views
14
>>> False in [0] 
True 
>>> type(False) == type(0) 
False 

私はこのつまずいた理由:私のユニットテストのためにPythonの "in"は型をチェックしていませんか?

が、私は私のタイプごとに有効と無効例の値のリストを作成しました。 (「私の型」とは、つまり、100%はPython型と同じではありません) すべての値のリストを反復して、それらが有効な値であれば渡すことを期待します。そうでなければ失敗する。私は最後の二つの「有効」の値と一致しない。もちろん、

>>> valid_values = [-1, 0, 1, 2, 3] 
>>> invalid_values = [True, False, "foo"] 
>>> for value in valid_values + invalid_values: 
...  if value in valid_values: 
...   print 'valid value:', value 
... 
valid value: -1 
valid value: 0 
valid value: 1 
valid value: 2 
valid value: 3 
valid value: True 
valid value: False 

を:今ではうまく機能しません 。

これは本当に私のvalid_valuesを反復して型を比較しなければならないのでしょうか?

+0

+1私はPythonの 'in'は型をチェックしませんが、決して私は決してありません。とても興味深い 。 。 。 – OnesimusUnbound

+0

@BenJames、うーん、私はそれがどのようにPythonでダックタイピングを壊すだろうか? – OnesimusUnbound

答えて

4

書かれている、「中」のコードは何をしていませんあなたはそれが欲しいです。あなたは別のものが必要です。

あなたは本当に、あなたがリストにタイプを含めることができます(チェックがまったく同じタイプのためです)型チェックをしたい場合は、次のサブタイプの取り扱い

>>> valid_values = [(int, i) for i in [-1, 0, 1, 2, 3]] 
>>> invalid_values = [True, False, "foo"] 
>>> for value in [v[1] for v in valid_values] + invalid_values: 
... if (type(value), value) in valid_values: 
...  print value, "is valid" 
... else: 
...  print value, "is invalid" 
... 
-1 is valid 
0 is valid 
1 is valid 
2 is valid 
3 is valid 
True is invalid 
False is invalid 
foo is invalid 
>>> 

もう少し困難であり、依存しますあなたがしたいことに

+0

私はあなたのソリューションを使用して、追加のループを防いでいます。 しかし、私はそれを次のように変更しました: valid_values = [(-1、0、1、2、3]のvの場合、(v) –

15

問題は欠落している型チェックではなく、boolintのサブクラスであるためです。これを試してみてください:

>>> False == 0 
True 
>>> isinstance(False, int) 
True 
+0

私はFalse == 0については不平を言っていませんが、 "in"はそのタイプをチェックしないという事実についてのみ言います。 –

+6

'in'は、シーケンス内の1つのアイテムが要求されたオブジェクトに対して' equal'であれば真を返します。つまり、問題は 'in'演算子ではなく、' == '演算子です。 – Constantinius

+0

私はちょうどそこにアイデンティティのチェックを持っていたいと思います。ループを使用せずにこれを行う方法はありますか? –

6

documentationによると、__contains__は、コレクションを反復処理し、==によって要素をテストすることによって行われます。したがって、実際の問題は、False == 0Trueであるという事実によって引き起こされます。

+0

ペタンティックのために... '' __contains __(self、thing) ''メソッドを最初にチェックしてから、*オブジェクトを反復するまでフォールバックします。本当の '' list''には、 '' __contains__''があります。したがって、フォールバックです。 –

+0

@GreggLindあなたはもちろん正しいです。しかし、私は "in"のより良い定義を見つけることができませんでした。とにかく驚くべきことの原則に従うために、オーバーロードされた '__contains__'メソッドは何とか似たようなことをするべきです。 –

+1

私は、封じ込めが発電機を使い切ったと判断したとき、そして/または永遠に走っているときに、この咬合を私に与えた。 *スマート* '' __contains__''を書くことで避けられます。 ( '' itertools.cycle''のようなものを考えてください) –

3

True == 1False == 0の2つを区別することは困難です。

アプローチ可能醜いワン(また、すべてのPython実装での動作が保証されていないが、CPythonの中でOKであるべき):他人として

>>> for value in valid_values + invalid_values: 
... if value in valid_values and not any(v is value for v in invalid_values): 
...  print ('valid value:', value) 
... 
valid value: -1 
valid value: 0 
valid value: 1 
valid value: 2 
valid value: 3 
+0

私は別のループを防ぐのが好きでした。このチェックは私のテストの大部分で非常に頻繁に実行されるので、 –

関連する問題