Pythonの「is」演算子を理解する


109

isオペレータは、変数の値が、インスタンス自身と一致していません。

それはどういう意味ですか?

2つの変数に名前xy付けて宣言し、両方の変数に同じ値を割り当てましたが、is演算子を使用するとfalseが返されます。

説明が必要です。これが私のコードです。

x = [1, 2, 3]
y = [1, 2, 3]

print(x is y)  # It prints false!

回答:


181

isオペレーターが何をテストするかを誤解しました。2つの変数が同じ値を持っているかどうかではなく、2つの変数が同じオブジェクトを指しているかどうかをテストします。

isオペレーターのドキュメントから:

事業者isis notオブジェクトのアイデンティティのためのテストは:x is y場合にのみ、真であるxy同じオブジェクトです。

==代わりに演算子を使用してください:

print(x == y)

これは印刷しTrueます。xおよびy2つの別個のリストです。

x[0] = 4
print(y)  # prints [1, 2, 3]
print(x == y)   # prints False

id()関数を使用すると、それが表示されxyさまざまな識別子が表示されます。

>>> id(x)
4401064560
>>> id(y)
4401098192

しかし、あなたが割り当てよyうとしたx場合、両方が同じオブジェクトを指します:

>>> x = y
>>> id(x)
4401064560
>>> id(y)
4401064560
>>> x is y
True

is両方が同じオブジェクトであることを示し、を返しますTrue

Pythonでは、名前は値を参照する単なるラベルであることに注意してください。複数の名前で同じオブジェクトを指すことができます。is2つの名前が1つの同じオブジェクトを指しているかどうかを示します。==2つの名前が同じ値を持つオブジェクトを参照しているかどうかを示します。


13
したがって、A is Bと同じid(A) == id(B)です。
imallett

2
@imallett:これは同じテストのプロキシです。ただしid(A)、変数に格納せず、後で動作することvariable == id(B)を期待している場合に限ります。Aその間に削除された場合B、同じメモリ位置が与えられる可能性があります。
Martijn Pieters

1
コメントでフォーマットできませんでした。でも面白いことがある。:) >>> x = 5 \n>>> y = 5 \n>>> x is y \nTrue \n>>> x == y \nTrue \n>>>\n
Haranadh

5
小さな整数は頻繁に使用されるため、CPythonでインターンされます。それは最適化です。x = 5; y = 5; xはy => id(x)== id(y)なのでTrueです。再利用されるのは同じ整数オブジェクトです。整数は不変なので、Pythonで動作します。x = 1.0を実行すると、y = 1.0またはx = 9999; y = 9999、floatとそれより大きい整数はインターンされないため、同じIDにはなりません。
MagnusLyckå2017

1
@MagnusLyckåには、不変オブジェクトがキャッシュされる原因となる可能性のある他の最適化があります。たとえば、新しい関数で、または対話型インタープリターで分離セミコロンと一緒に例を実行すると、それらも同じIDを持つことがわかります。
Martijn Pieters

60

別の重複は、なぜ2つの等しい文字列が一般に同一でないのかを尋ねていましたが、実際にはここでは答えられません。

>>> x = 'a' 
>>> x += 'bc'
>>> y = 'abc'
>>> x == y
True
>>> x is y
False

では、なぜ同じ文字列ではないのでしょうか。特にこれを考えると:

>>> z = 'abc'
>>> w = 'abc'
>>> z is w
True

2番目の部分を少し延期しましょう。どうして最初のものが真実なのでしょうか?

インタプリタには、「インターニングテーブル」、つまり文字列値を文字列オブジェクトにマッピングするテーブルが必要です。そのため、内容を使用して新しい文字列を作成しようとするたびに'abc'、同じオブジェクトが返されます。ウィキペディアには、インターンの仕組みに関するより詳細な議論があります。

また、Python は文字列インターニングテーブルがあります。sys.internメソッドで文字列を手動でインターンできます。

実際、Pythonは不変タイプを自動的にインターンすること許可されていますが、そうする必要はありません。実装が異なれば、異なる値がインターンされます。

CPython(使用している実装がわからない場合に使用している実装)は、小さな整数とのようないくつかの特別なシングルトンを自動インターンしますFalseが、文字列(または大きな整数、小さなタプル、またはその他のもの)は自動インターンしません。あなたはこれをかなり簡単に見ることができます:

>>> a = 0
>>> a += 1
>>> b = 1
>>> a is b
True
>>> a = False
>>> a = not a
>>> b = True
a is b
True
>>> a = 1000
>>> a += 1
>>> b = 1001
>>> a is b
False

OKが、なぜだったzw同じ?

それはインタープリターが自動的にインターンするのではなく、コンパイラーが値をフォールディングすることです。

同じコンパイル時の文字列は、(同じモジュールに2回出現した場合は、まさにこの意味するので、文字列リテラルと同じものではありません、それは、定義するのは難しいですr'abc''abc''a' 'b' 'c'理解しやすい、すべての異なるリテラルが、同じ文字列が、しかし、直感的に)、コンパイラーは、2つの参照を持つ文字列のインスタンスを1つだけ作成します。

実際、コンパイラーはさらに先に進む'ab' + 'c'ことができます。'abc'オプティマイザーによって変換できます。その場合'abc'、同じモジュール内の定数と一緒に折りたたむことができます。

繰り返しますが、これはPythonで許可されているものですが、必須ではありません。しかし、この場合、CPythonは常に小さな文字列(および、たとえば、小さなタプル)を折りたたみます。(ただし、対話型インタープリターのステートメントごとのコンパイラーは、モジュール単位のコンパイラーと同じ最適化を実行しないため、対話的に同じ結果が表示されることはありません。)


では、プログラマーとしてこれについて何をすべきでしょうか?

ええと…何も。2つの不変値が同一であるかどうかを気にする理由はほとんどありません。のa is b代わりにいつ使用できるかを知りたいa == b場合は、間違った質問をしています。次のa == b2つの場合を除いて、常に使用します。

  • のようなシングルトン値とのより読みやすい比較のためにx is None
  • 変更可能な値の場合、変更xがに影響するかどうかを知る必要がある場合y

1
素晴らしい説明、特に最後のアドバイス。
DavidG

詳しい説明ありがとうございます。誰かのノウハウを行います場合wz理由値を折るコンパイラで同一であり、その理由であっても使用して、REPLでこのも作業を行いid()参照をチェックしますか?Pythonの3.7でREPLを使用して
カイカイ

8

isそれらが実際に同じオブジェクトである場合にのみtrueを返します。それらが同じである場合、一方への変更はもう一方にも表示されます。これが違いの例です。

>>> x = [1, 2, 3]
>>> y = [1, 2, 3]
>>> print x is y
False
>>> z = y
>>> print y is z
True
>>> print x is z
False
>>> y[0] = 5
>>> print z
[5, 2, 3]

8

重複する質問によって促されて、この類推はうまくいくかもしれません:

# - Darling, I want some pudding!
# - There is some in the fridge.

pudding_to_eat = fridge_pudding
pudding_to_eat is fridge_pudding
# => True

# - Honey, what's with all the dirty dishes?
# - I wanted to eat pudding so I made some. Sorry about the mess, Darling.
# - But there was already some in the fridge.

pudding_to_eat = make_pudding(ingredients)
pudding_to_eat is fridge_pudding
# => False

3
単なる個人的な好みかもしれません(しゃれは意図されていません)が、このアナロジーは役に立たないよりも混乱し、冷蔵庫に何もないときにプリンを食べたくなった:(退屈ですが、Mark Ransomの答えはおそらくより有益です
トムクローズ

1
@TomClose:この質問には多くのすばらしい回答があります。また、プリンも欲しいです。
アマダン

5

isis notPythonの2つの識別演算子です。is演算子は変数の値を比較しませんが、変数のIDを比較します。このことを考慮:

>>> a = [1,2,3]
>>> b = [1,2,3]
>>> hex(id(a))
'0x1079b1440'
>>> hex(id(b))
'0x107960878'
>>> a is b
False
>>> a == b
True
>>>

アイデンティティは(もCPythonとのメモリアドレスを指定できます)の両方のために異なっていることが、上記の例が示すあなたab(それらの値が同じであっても)。これがa is b、両方のオペランドのIDの不一致によりfalseを返すと言う理由です。ただし、と言うとa == b==両方のオペランドに同じ値が割り当てられているかどうかを演算で検証するだけなので、trueを返します。

興味深い例(追加グレードの場合):

>>> del a
>>> del b
>>> a = 132
>>> b = 132
>>> hex(id(a))
'0x7faa2b609738'
>>> hex(id(b))
'0x7faa2b609738'
>>> a is b
True
>>> a == b
True
>>>

上記の例では、aおよびbは2つの異なる変数ですが、がa is b返されTrueます。これは、タイプのためであるaIS int不変オブジェクトです。したがって、Python(メモリを節約すると思います)bは、同じ値で作成されたときに同じオブジェクトを割り当てました。したがって、この場合、変数のIDは一致し、であることa is bが判明しましたTrue

これはすべての不変オブジェクトに適用されます:

>>> del a
>>> del b
>>> a = "asd"
>>> b = "asd"
>>> hex(id(a))
'0x1079b05a8'
>>> hex(id(b))
'0x1079b05a8'
>>> a is b
True
>>> a == b
True
>>>

お役に立てば幸いです。


これは本当に良い例です。詳細情報をありがとう。
Haranadh 2017

ただし、a = 123456789 b = 123456789を試してください
user2183078

Python -5よりも低い、または高いもの256はすべてFalseになります。Pythonは[-5、256]の範囲の数値をキャッシュします。
スマート

表示されているようにすべての不変オブジェクトが共有されるわけではありません。これは、一部のオブジェクトに対してPythonランタイムによって適用される最適化で、他のオブジェクトには適用されません。小さな整数を共有するプロセスは十分に文書化されていますが、それは文字列のインターン用ではないと思います。
Mark Ransom

4

x is yid(x) == id(y)オブジェクトのアイデンティティを比較すると同じです。

@ tomasz-kurganが以下のコメントで指摘しているisように、演算子は特定のオブジェクトで異常に動作します。

例えば

>>> class A(object):
...   def foo(self):
...     pass
... 
>>> a = A()
>>> a.foo is a.foo
False
>>> id(a.foo) == id(a.foo)
True

参照;
https://docs.python.org/2/reference/expressions.html#is-not
https://docs.python.org/2/reference/expressions.html#id24


そうではありません。ほとんどの場合、同様に動作する可能性がありますが、常に正しいとは限りません。これを参照してください-ページの最下部、箇条書き6 .:>(...)、is演算子の特定の使用法では、インスタンスメソッドまたは定数間の比較を含むものなど、一見異常な動作に気付く場合があります: `class A(object):def foo(self):pass a = A()print a.foo is a.foo print id(a.foo)== id(a.foo)`
Tomasz Kurgan

3

あなたがここで小さな整数にチェックすることができるので。257を超える数値は小さな整数ではないため、別のオブジェクトとして計算されます。

==この場合は、代わりに使用することをお勧めします。

詳細はこちら:http : //docs.python.org/2/c-api/int.html


2

Xは配列を指し、Yは別の配列を指します。それらの配列は同一ですが、isオペレーターはそれらのポインターを調べますが、それらは同一ではありません。


5
Pythonにはポインターがありません。用語を厳しくする必要があります。
David Heffernan

3
内部的には、Javaや他の多くの言語と同じように動作します。実際、isオペレーターの機能はこれを示しています。
Neko

5
実装の詳細は重要ではありません。ドキュメントでは「オブジェクトID」という用語を使用しています。だからあなたがする必要があります。「演算子はオブジェクトの同一性のテストであり、テストではありません。xとyが同じオブジェクトである場合に限り、x is yはtrueです。xがyでない場合、逆の真理値が得られます。」
David Heffernan

1
@猫:CPythonは内部的にポインターを使用します。しかし、明らかにJython(Javaで実装)およびPyPy(Pythonのサブセットで実装)はポインターを使用しません。PyPyでは、id要求しない限り、一部のオブジェクトにはもありません。
abarnert 2014

1

オブジェクトの同一性、つまり変数がメモリ内の同じオブジェクトを参照しているかどうかを比較します。これ==はJavaまたはC のようなものです(ポインターを比較する場合)。


1

果物の簡単な例

fruitlist = [" apple ", " banana ", " cherry ", " durian "]
newfruitlist = fruitlist
verynewfruitlist = fruitlist [:]
print ( fruitlist is newfruitlist )
print ( fruitlist is verynewfruitlist )
print ( newfruitlist is verynewfruitlist )

出力:

True
False
False

あなたがしようとすると

fruitlist = [" apple ", " banana ", " cherry ", " durian "]
newfruitlist = fruitlist
verynewfruitlist = fruitlist [:]
print ( fruitlist == newfruitlist )
print ( fruitlist == verynewfruitlist )
print ( newfruitlist == verynewfruitlist )

出力は異なります。

True
True
True

これは、==演算子が変数の内容のみを比較するためです。2つの変数のIDを比較するには、is演算子を使用します

識別番号を印刷するには:

print ( id( variable ) )

-3

isオペレータは何もなく、英語版ではありません==。2つのリストのIDが異なるため、答えはfalseです。あなたが試すことができます:

a=[1,2,3]
b=a
print(b is a )#True

*両方のリストのIDが同じになるため


is「の英語版ではありません==
デヴィッド・バック
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.