Python 3 では、異なる値で初期化された範囲が互いに等しいと判断されるのはなぜですか?
インタープリターで次のコマンドを実行すると:
>>> r1 = range(0)
>>> r2 = range(2, 2, 2)
>>> r1 == r2
True
結果は ですTrue
。なぜそうなるのでしょうか?range
異なるパラメータ値を持つ 2 つの異なるオブジェクトが同等として扱われるのはなぜでしょうか?
ベストアンサー1
オブジェクトはrange
特別です:
Pythonは比較しますrange
オブジェクトとしてシーケンスつまり、比較は評価しないどうやってそれらは与えられたシーケンスを表すのではなく、何彼らが代表する。
start
、stop
パラメータが完全に異なるという事実はstep
ここでは何ら影響を及ぼさない。展開するとすべて空のリストを表す:
たとえば、最初のrange
オブジェクト:
list(range(0)) # []
そして2番目のrange
オブジェクト:
list(range(2, 2, 2)) # []
どちらも空のリストを表す2つの空のリストは等しい(True
)のでrange
、代表する彼ら。
その結果、全く異なる見ている range
オブジェクトが同じシーケンスを表す場合は、比較する等しい:
range(1, 5, 100) == range(1, 30, 100)
どちらも 1 つの要素を持つリストを表す[1]
ため、これら 2 つは等しいと評価されます。
いいえ、range
オブジェクトは本当に特別:
ただし、比較では評価されないことに注意してくださいどうやってこれらは比較の結果のシーケンスを表します達成することができます使用して専らの値はstart
、オブジェクトのstep
とともに、比較の速度に関して非常に興味深い意味を持ちます。len
range
r0 = range(1, 1000000)
r1 = range(1, 1000000)
l0 = list(r0)
l1 = list(r1)
範囲を超高速で比較します:
%timeit r0 == r1
The slowest run took 28.82 times longer than the fastest. This could mean that an intermediate result is being cached
10000000 loops, best of 3: 160 ns per loop
一方、リストは..
%timeit l0 == l1
10 loops, best of 3: 27.8 ms per loop
うん..
としてフォロー注意してください、これはPython 3のrangeオブジェクトにのみ適用されます。Python 2はrange()
リストを返す単純な関数ですが、2.x
xrange
オブジェクトには比較機能がありません(これらだけではありません。)range
です。
見る@ajcr の回答Python 3オブジェクトのソースコードから直接引用しますrange
。そこには、2つの異なる範囲の比較が実際に何を意味するかが文書化されています。シンプルで素早い操作。range_equals
機能は、range_richcompare
関数およびケースに割り当てられEQ
、NE
tp_richcompare
PyRange_Type
型用のスロット。
の実装は、range_equals
ここに追加するとかなり読みやすくなると思います (シンプルで良いため)。
/* r0 and r1 are pointers to rangeobjects */
/* Check if pointers point to same object, example:
>>> r1 = r2 = range(0, 10)
>>> r1 == r2
obviously returns True. */
if (r0 == r1)
return 1;
/* Compare the length of the ranges, if they are equal
the checks continue. If they are not, False is returned. */
cmp_result = PyObject_RichCompareBool(r0->length, r1->length, Py_EQ);
/* Return False or error to the caller
>>> range(0, 10) == range(0, 10, 2)
fails here */
if (cmp_result != 1)
return cmp_result;
/* See if the range has a lenght (non-empty). If the length is 0
then due to to previous check, the length of the other range is
equal to 0. They are equal. */
cmp_result = PyObject_Not(r0->length);
/* Return True or error to the caller.
>>> range(0) == range(2, 2, 2) # True
(True) gets caught here. Lengths are both zero. */
if (cmp_result != 0)
return cmp_result;
/* Compare the start values for the ranges, if they don't match
then we're not dealing with equal ranges. */
cmp_result = PyObject_RichCompareBool(r0->start, r1->start, Py_EQ);
/* Return False or error to the caller.
lens are equal, this checks their starting values
>>> range(0, 10) == range(10, 20) # False
Lengths are equal and non-zero, steps don't match.*/
if (cmp_result != 1)
return cmp_result;
/* Check if the length is equal to 1.
If start is the same and length is 1, they represent the same sequence:
>>> range(0, 10, 10) == range(0, 20, 20) # True */
one = PyLong_FromLong(1);
if (!one)
return -1;
cmp_result = PyObject_RichCompareBool(r0->length, one, Py_EQ);
Py_DECREF(one);
/* Return True or error to the caller. */
if (cmp_result != 0)
return cmp_result;
/* Finally, just compare their steps */
return PyObject_RichCompareBool(r0->step, r1->step, Py_EQ);
私自身のコメントもここにいくつか載せました。@ajcr の回答Python の同等のもの。