web-dev-qa-db-ja.com

なぜ(0-6)は-6 = Falseですか?

可能性のある複製:
Pythonの「is」演算子は整数で予期しない動作をします

今日、私は自分のプロジェクトをデバッグしようとしました、そして、数時間の分析の後、私はこれを得ました:

>>> (0-6) is -6
False

だが、

>>> (0-5) is -5
True

なぜ説明してもらえますか?多分これはある種のバグまたは非常に奇妙な動作です。

> Python 2.7.3 (default, Apr 24 2012, 00:00:54) [GCC 4.7.0 20120414 (prerelease)] on linux2
>>> type(0-6) 
<type 'int'>
>>> type(-6) 
<type 'int'>
>>> type((0-6) is -6)
<type 'bool'>
>>> 
130

-5から256までのすべての整数は、CPythonと同じアドレスを共有するグローバルオブジェクトとしてキャッシュされるため、isテストに合格します。

このアーティファクトは http://www.laurentluce.com/posts/python-integer-objects-implementation/ で詳細に説明されており、現在のソースコードを http: //hg.python.org/cpython/file/tip/Objects/longobject.c

特定の構造を使用して小さな整数を参照し、それらを共有して、アクセスを高速化します。これは整数オブジェクトへの262ポインタの配列です。これらの整数オブジェクトは、上で見た整数オブジェクトのブロックで初期化中に割り当てられます。小さな整数の範囲は-5から256です。多くのPython=プログラムは、その範囲の整数を使用して多くの時間を費やすため、これは賢明な決定です。

これはCPythonの実装の詳細であり、これに依存するべきではありません。たとえば、 PyPyid自分自身を返す整数なので、(0-6) is -6は、内部で「異なるオブジェクト」であっても常にtrueです。また、この整数キャッシュを有効にするかどうかを構成したり、下限と上限を設定したりすることもできます。ただし、一般に、異なるオリジンから取得されたオブジェクトは同一ではありません。同等性を比較したい場合は、==

151
kennytm

Pythonは、インタプリタに-5〜256の範囲の整数を格納します。これには、これらの整数が返される整数オブジェクトのプールがあります。そのため、これらのオブジェクトは同じです:(0-5)-5はその場で作成されるため、(0-6)-6は異なります。

CPythonのソースコードのソースは次のとおりです。

#define NSMALLPOSINTS           257
#define NSMALLNEGINTS           5
static PyIntObject *small_ints[NSMALLNEGINTS + NSMALLPOSINTS];

CPythonソースコードを表示/trunk/Objects/intobject.c)。ソースコードには、次のコメントが含まれています。

/* References to small integers are saved in this array so that they
   can be shared.
   The integers that are saved are those in the range
   -NSMALLNEGINTS (inclusive) to NSMALLPOSINTS (not inclusive).
*/

次に、is演算子はそれらを比較します(-5)は同じオブジェクト(同じメモリロケーション)ですが、他の2つの新しい整数(-6)は異なるメモリにあるためです場所(そしてisTrueを返しません)。上記のソースコードの257は正の整数用であるため、0 - 256(包括的)であることに注意してください。

ソース

29
Simeon Visser

バグではありません。 isは同等性テストではありません。 ==は期待される結果を与えます。

この動作の技術的な理由は、Python実装は、同じ定数値の異なるインスタンスを同じオブジェクトまたは異なるオブジェクトとして自由に処理できることです。Python使用している実装は、メモリを節約するために、特定の小さな定数が同じオブジェクトを共有するように選択します。この動作がバージョン間またはバージョン間で同じであることに依存することはできませんPython =実装。

26

これは、CPythonがいくつかの小さな整数と小さな文字列をキャッシュし、そのオブジェクトのすべてのインスタンスに同じid()を与えるために起こります。

_(0-5)_と_-5_のid()の値は同じですが、_0-6_と_-6_には当てはまりません

_>>> id((0-6))
12064324
>>> id((-6))
12064276
>>> id((0-5))
10022392
>>> id((-5))
10022392
_

同様に文字列の場合:

_>>> x = 'abc'
>>> y = 'abc'
>>> x is y
True
>>> x = 'a little big string'
>>> y = 'a little big string'
>>> x is y
False
_

文字列のキャッシュの詳細については、次を参照してください。 is演算子は、文字列とスペースを比較した場合の動作が異なります

17