11

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

私は次のPythonの奇妙さに出くわしました:

>>> two = 2
>>> ii = 2

>>> id(two) == id(ii)
True
>>> [id(i) for i in [42,42,42,42]]
[10084276, 10084276, 10084276, 10084276]

>>> help(id)
Help on built-in function id in module __builtin__:

id(...)
    id(object) -> integer

    Return the identity of an object.  This is guaranteed to be unique among
    simultaneously existing objects.  (Hint: it's the object's memory address.)
  1. すべての番号は一意のオブジェクトですか?
  2. 同じ要素値(たとえば、2、ii)を保持する異なる変数は同じオブジェクトですか?
  3. Pythonによって生成された数値のIDはどのようになっていますか?
  4. 上記の例では、値2を保持しているメモリセルへの2つおよびiiのポインタはありますか?それは非常に奇妙でしょう。

このアイデンティティの危機を解くのを手伝ってください。

さらにいくつかの奇妙な点:

>>> a,b=id(0),id(1)
>>> for i in range(2,1000):
   a,b=b,id(i)
   if abs(a-b) != 12:
    print('%i:%i -> %i' % (i,a,b))

上記のコードは、連続する整数のIDも連続しているかどうかを調べ、異常を出力します。

77:10083868 -> 10085840
159:10084868 -> 10086840
241:10085868 -> 10087840
257:10087660 -> 11689620
258:11689620 -> 11689512
259:11689512 -> 11689692
260:11689692 -> 11689548
261:11689548 -> 11689644
262:11689644 -> 11689572
263:11689572 -> 11689536
264:11689536 -> 11689560
265:11689560 -> 11689596
266:11689596 -> 11689656
267:11689656 -> 11689608
268:11689608 -> 11689500
331:11688756 -> 13807288
413:13806316 -> 13814224
495:13813252 -> 13815224
577:13814252 -> 13816224
659:13815252 -> 13817224
741:13816252 -> 13818224
823:13817252 -> 13819224
905:13818252 -> 13820224
987:13819252 -> 13821224

パターンは413以降に出現することに注意してください。おそらく、新しいメモリページの先頭にあるブードゥーアカウンティングが原因である可能性があります。

4

5 に答える 5

9

-1から255(?)までの整数、および文字列リテラルがインターンされます。ソース内の各インスタンスは、実際には同じオブジェクトを表します。

CPythonでは、の結果はid()PyObjectのプロセススペース内のアドレスです。

于 2010-01-13T17:47:20.980 に答える
8

Pythonのすべての実装は、あらゆる範囲で最適化することが完全に許可されています(....まったくなし;-)不変オブジェクト(数値、タプル、文字列など)のIDと割り当て[[可変オブジェクトにはそのような許容範囲はありません。リスト、ディクテーション、セットなど]]。

2つの不変オブジェクト参照aとの間bで、実装が保証する必要があるのは次のとおりです。

  1. id(a) == id(b)、別名a is b、常に意味する必要がありますa == b
  2. したがって、常にAKAa != bを意味する必要がありますid(a) != id(b)a is not b

特に、不変の型であっても、暗示する必要のある制約がないことに注意してください(つまり、)。その保証のみを行います(したがって、ではなく常にテストできます)。a == ba is bid(a) == id(b)Noneif x is None:if x == None:

id現在のCPython実装は、特定の範囲内の小さな整数と、リテラルが特定の範囲内に複数回出現する組み込みの不変型オブジェクトを「マージ」する(つまり、単一の割り当てを持つ)ことにより、これらの自由度を利用しています。関数(たとえば、関数fにリテラルが4つある場合、それらはすべて関数の定数内の'foobar'文字列の単一インスタンスを参照し、その定数の4つの同一であるが別々のコピーを格納する許容される実装と比較して少しスペースを節約します)。'foobar'

これらの実装に関する考慮事項はすべて、Pythonコーダーにとってはあまり重要ではありません(Python実装、または少なくともデバッグシステムなどの特定の実装に緊密にバインドされているものを使用している場合を除く)。

于 2010-01-13T19:08:02.657 に答える
4

4番目の質問「上記の例では、値2を保持しているメモリセルへの2つとiiのポインタは非常に奇妙です」は、全体を理解するための鍵です。

Cのような言語に精通している場合、Pythonの「変数」は実際には同じようには機能しません。次のようなAC変数宣言:

int j=1;
int k=2;
k += j;

「コンパイラ、スタック上の2つのメモリ領域を予約します。それぞれに整数を保持するのに十分なスペースがあり、一方を「j」、もう一方を「k」として記憶します。次に、jに値「1」を入力します。値が「2」のk。」実行時に、コードは「kの整数の内容を取得し、jの整数の内容を追加して、結果をkに格納する」と言います。

Pythonで一見同等のコード:

j = 1
k = 2
k += j

「Python、「1」という名前のオブジェクトを検索し、それを指す「j」というラベルを作成します。「2」というオブジェクトを検索し、「k」という名前のラベルを作成します。ここで、オブジェクト'k'が( '2')を指し、オブジェクト'j'が( '1')を指し、'k'が'add'操作を実行した結果のオブジェクトを指すようにします。二人で。」

このコードを(disモジュールを使用して)逆アセンブルすると、次のようになります。

  2           0 LOAD_CONST               1 (1)
              3 STORE_FAST               0 (j)

  3           6 LOAD_CONST               1 (2)
              9 STORE_FAST               1 (k)

  4          12 LOAD_FAST                1 (k)
             15 LOAD_FAST                0 (j)
             18 INPLACE_ADD
             19 STORE_FAST               1 (k)

そうです、Pythonの「変数」は、データで埋めることができる コンテナーではなく、オブジェクトを指すラベルです。

他の3つの質問はすべて、「Pythonがコードの一部から新しいオブジェクトを作成するのはいつか、既存のオブジェクトをいつ再利用するのか」のバリエーションです。後者は「インターン」と呼ばれます。(Pythonでは)シンボル名のように見える小さな整数や文字列に発生します。

于 2010-01-13T18:23:50.657 に答える
2

この種の調査には十分注意する必要があります。あなたは言語の実装の内部を調べていますが、それらは保証されていません。ヘルプidはスポットオンです。番号は2つの異なるオブジェクトでは異なり、同じオブジェクトでは同じになります。実装の詳細として、CPythonではオブジェクトのメモリアドレスです。CPythonは、いつでもこの詳細を変更することを決定する可能性があります。

同じ割り当て時間にインターンされる小整数の詳細も、いつでも変更される可能性のある詳細です。

また、CPythonからJython、PyPy、またはIronPythonに切り替えると、のドキュメントを除いて、すべての賭けがオフになりますid()

于 2010-01-13T17:55:49.683 に答える
1

すべての数値が一意のオブジェクトであるとは限りません。一部の数値がCPythonインタープリターの最適化の詳細であるという事実があります。 この動作に依存しないでください。isさらに言えば、平等をテストするために使用しないでください。isまったく同じオブジェクトが必要であることが絶対に確実な場合にのみ使用してください。

于 2010-01-13T18:03:08.980 に答える