131

重複の可能性:
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'>
>>> 
4

4 に答える 4

154

-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 です。また、この整数キャッシュを有効にするかどうかを構成したり、下限と上限を設定したりすることもできます。ただし、一般に、異なるオリジンから取得されたオブジェクトは同一ではありません。同等性を比較したい場合は、 を使用してください==

于 2012-07-13T18:29:38.370 に答える
30

Python は、-5 から 256 の範囲の整数をインタープリターに格納します。これには、これらの整数が返される整数オブジェクトのプールがあります。そのため、これらのオブジェクトは同じですが、(0-5)and-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が同じオブジェクト (同じメモリ位置) であるため、等しいものとして比較します-6( 上記のソースコードは正の整数用であるため、(包括的)であることに注意してください。isTrue2570 - 256

ソース

于 2012-07-13T18:30:25.867 に答える
27

バグではありません。isは平等テストではありません。==期待される結果が得られます。

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

于 2012-07-13T18:30:13.210 に答える
17

これは、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列とスペースを比較する場合、演算子の動作が異なります

于 2012-07-13T18:31:40.067 に答える