「==」または「is」のいずれかを使用して文字列を比較すると、異なる結果になることがあるのはなぜですか?


1147

2つの変数が値に設定されているPythonプログラムを持っています'public'。条件式では比較var1 is var2に失敗しますが、これに変更するvar1 == var2とが返されますTrue

Pythonインタープリターを開いて同じ「is」比較を実行すると、成功します。

>>> s1 = 'public'
>>> s2 = 'public'
>>> s2 is s1
True

ここで何が欠けていますか?



3
この問題は、たとえばを介してコンソール入力を読み取った場合にも発生しますinput = raw_input("Decide (y/n): ")。この場合、「y」を入力if input == 'y':すると「True」if input is 'y':が返され、Falseが返されます。
SemjonMössinger16年

4
このブログは、どの回答よりもはるかに完全な説明を提供していますguilload.com/python-string-interning
Chris_Rands

1
クリス・リコは言及ここで、私の偉大な説明@のようstackoverflow.com/q/15541404/1695680
ThorSummoner

回答:


1533

isアイデンティティテストで==あり、平等テストです。あなたのコードで何が起こるかはこのようなインタプリタでエミュレートされます:

>>> a = 'pub'
>>> b = ''.join(['p', 'u', 'b'])
>>> a == b
True
>>> a is b
False

だから、彼らが同じではないのも不思議ではありませんよね?

つまりisid(a) == id(b)


17
ああeqと同じ?対等しい?スキームでは、それを得た。
jottos

47
またはJavaで==.equals()。最良の部分は、Python ==がJavaに類似していないことです==
MatrixFrog

11
@Крайст:単一のNone値しかありません。そのため、常に同じIDを持ちます。
SilentGhost 2012年

18
これは、OPの「is-> True」の例には対応していません。
user2864740 2014

6
@AlexanderSupertramp、文字列インターンのため。
Chris Rico

570

ここでの他の答えは正解です。これisは、アイデンティティの比較に==使用され、同等性の比較に使用されます。重要なのは等価(2つの文字列に同じ文字が含まれている必要がある)であるため、この場合はis演算子が間違っているため、==代わりに使用する必要があります。

is対話的に動作する理由は、(ほとんどの)文字列リテラルがデフォルトでインターンされるためです。ウィキペディアから:

インターンされた文字列は、文字列の比較を高速化します。これは、文字列キーを持つハッシュテーブルに大きく依存するアプリケーション(コンパイラや動的プログラミング言語ランタイムなど)でパフォーマンスのボトルネックになることがあります。インターンせずに、2つの異なる文字列が等しいことを確認するには、両方の文字列のすべての文字を調べる必要があります。これはいくつかの理由で遅くなります。文字列の長さは本質的にO(n)です。通常は、メモリのいくつかの領域からの読み取りが必要であり、時間がかかります。読み取りによりプロセッサキャッシュがいっぱいになるため、他のニーズに使用できるキャッシュが少なくなります。インターンされた文字列では、元のインターン操作の後に単純なオブジェクトIDテストで十分です。これは通常、ポインタ等価テストとして実装されます。

したがって、同じ値を持つ2つの文字列リテラル(プログラムのソースコードに文字どおりに入力され、引用符で囲まれた単語)がプログラムにある場合、Pythonコンパイラは自動的に文字列をインターンし、両方を同じ場所に格納しますメモリの場所。(これは常にではないことに注意してください発生するとはず、発生時のルールは非常に複雑なので、本番用コードではこの動作に依存しないでください!)

インタラクティブセッションでは、両方の文字列が実際には同じメモリの場所に格納されるため、これらの文字列は同じIDを持ち、is演算子は期待どおりに機能します。しかし、他の方法で文字列を作成した場合(その文字列にまったく同じ文字が含まれている場合でも)、その文字列は等しい可能性がありますが、同じ文字列ではありません。つまり、IDが異なるため、メモリ内の別の場所に保存されます。


6
文字列がインターンされるときの複雑なルールの詳細をどこで読むことができますか?
Noctisスカイタワー2013

89
完全な説明のための+1。実際に何が起こったかを説明せずに、他の回答がどのように多くの賛成票を受け取ったかはわかりません。
That1Guy 2013

4
これは私が質問を読んだときに私が考えたこととまったく同じです。受け入れられた答えは短いですが事実が含まれていますが、この答え事柄をはるかによく説明しています。いいね!
Sнаđошƒаӽ

3
@NoctisSkytowerも同じようにGoogle
xtreak

5
@ naught101:いいえ、ルールが間を選択することです==し、isあなたが望むチェックの種類に基づいています。文字列が等しい(つまり、内容が同じ)場合は、常にを使用する必要があります==。2つのPython名が同じオブジェクトインスタンスを参照しているかどうかを気にする場合は、を使用する必要がありますis。あなたは、必要があるかもしれませんis、その内容を気にすることなく、異なる値のハンドルの多くは、または他の何かの一つだけが知っているならば、あなたはその事を装って他のオブジェクトを無視するということであれば、あなたにしている書き込みコードを。不明な場合は、常にを選択してください==
Daniel Pryden 2016年

108

isキーワードは、オブジェクトIDしばらくのためのテストです==値の比較です。

を使用するisと、オブジェクトが同じオブジェクトである場合にのみ、結果はtrueになります。ただし、==オブジェクトの値が同じである場合は常にtrueになります。


57

最後に注意すべきことはsys.intern、同じ文字列への参照を確実に取得するために関数を使用することです:

>>> from sys import intern
>>> a = intern('a')
>>> a2 = intern('a')
>>> a is a2
True

上記で指摘したように、is文字列の等価性を判断するためにを使用するべきではありません。しかし、これは、使用するなんらかの奇妙な要件があるかどうかを知るのに役立ちますis

このintern関数は以前はPython 2に組み込まれていましたがsys、Python 3のモジュールに移動されたことに注意してください。


43

isアイデンティティテストで==あり、平等テストです。これが意味するのは、is2つのものが同じものであるか、まったく同じであるかを確認する方法です。

単純なpersonオブジェクトを持っているとしましょう。それが「ジャック」と名付けられ、「23」歳である場合、それは別の23歳のジャックと同等ですが、同じ人物ではありません。

class Person(object):
   def __init__(self, name, age):
       self.name = name
       self.age = age

   def __eq__(self, other):
       return self.name == other.name and self.age == other.age

jack1 = Person('Jack', 23)
jack2 = Person('Jack', 23)

jack1 == jack2 #True
jack1 is jack2 #False

彼らは同じ年齢ですが、同じ人物ではありません。文字列は別の文字列と同等かもしれませんが、同じオブジェクトではありません。


セットを変更してもjack1.age = 99、変更されませんjack2.age。これは、2つの異なるインスタンスであるためjack1 is not jack2です。ただし、jack1 == jack2名前と年齢が同じである場合、それらは互いに同等である可能性があります。Pythonでは文字列が不変であり、Pythonは同じインスタンスを再利用することが多いため、文字列の場合はさらに複雑になります。特別なケース(文字列)ではなく単純なケース(通常のオブジェクト)を使用するため、この説明が好きです。
Flimm

37

これは余談ですが、慣用的なpythonでは、次のようなことがよくあります。

if x is None: 
    # some clauses

Nullオブジェクトのインスタンスが1つあることが保証されているため(つまり、None)、これは安全です。


1
TrueとFalseは同じですか?1つのインスタンスだけなので、一致しますか?
HandyManDan 2018年

1
@HandyManDanはい、彼らはパイソン2及び3の両方シングルトンです
kamillitw

@kamillitwですが、Python 2ではFalseとTrueを再割り当てできます。
Martijn Pieters

28

何をしているかわからない場合は、「==」を使用してください。それについてもう少し知識がある場合は、「なし」などの既知のオブジェクトに「is」を使用できます。

そうでなければ、なぜ物事がうまくいかないのか、なぜこれが起こるのか不思議に思うでしょう:

>>> a = 1
>>> b = 1
>>> b is a
True
>>> a = 6000
>>> b = 6000
>>> b is a
False

いくつかのpythonバージョン/実装間で同じであることが保証されているかどうかさえわかりません。


1
intの再割り当てがこの条件をトリガーする方法を示す興味深い例です。なぜこれが失敗したのですか?それはインターンなどによるものですか?
ポール

:それは返す偽のインタプリタの実装に起因することがある理由のように見えるstackoverflow.com/questions/132988/...
ポール・


@ArchitJainはい、これらのリンクはそれをかなりよく説明しています。あなたがそれらを読むとき、あなたはあなたが「何が」使用できるのかを知っているでしょう。私は彼らがそれをするのがまだ良い考えではない理由を説明してほしいと思います:)これは他の人もそうすることを仮定するのが良い考えではないことを知っています(または内部化された数値範囲は決して変わらないでしょう)
マティアス・ニルソン

20

私のpythonの限られた経験から、is2つのオブジェクトを比較して、同じ値を持つ2つの異なるオブジェクトではなく、同じオブジェクトであるかどうかを確認するために使用されます。 ==値が同じかどうかを判断するために使用されます。

ここに良い例があります:

>>> s1 = u'public'
>>> s2 = 'public'
>>> s1 is s2
False
>>> s1 == s2
True

s1Unicode文字列でありs2、通常の文字列です。それらは同じタイプではありませんが、同じ値です。


17

「is」比較がfalseと評価された場合、2つの異なるオブジェクトが使用されるという事実に関係していると思います。trueと評価された場合、それは内部で同じオブジェクトを使用しており、新しいオブジェクトを作成していないことを意味します。おそらく、2秒程度の時間内に作成したため、最適化との間に大きな時間ギャップがないためです。同じオブジェクトを使用します。

これが、文字列オブジェクトの値を比較するためにでは==なくis、等号演算子を使用する必要がある理由です。

>>> s = 'one'
>>> s2 = 'two'
>>> s is s2
False
>>> s2 = s2.replace('two', 'one')
>>> s2
'one'
>>> s2 is s
False
>>> 

この例では、以前は 'one'に等しい別の文字列オブジェクトであったs2を作成しましたが、これは次のものと同じオブジェクトではありません。 s最初は 'one'に割り当てなかったため、インタープリターが同じオブジェクトを使用しなかったため、これはと同じオブジェクトではありません。私が持っていたら、それらを同じオブジェクトにしたでしょう。


3
.replace()ただし、このコンテキストでの例としての使用は、その意味論が混乱する可能性があるため、おそらく最善ではありません。 s2 = s2.replace()常に新しい文字列オブジェクトを作成し、新しい文字列オブジェクトをに割り当ててからs2s2ポイントしていた文字列オブジェクトを破棄します。したがって、たとえそうしたとしてもs = s.replace('one', 'one')、新しい文字列オブジェクトを取得することになります。
Daniel Pryden、2009年

13

これは「抑留された」文字列として知られていると思います。Pythonはこれを行い、Javaも同様に、最適化モードでコンパイルする場合はCおよびC ++も行います。

2つの同じ文字列を使用する場合、2つの文字列オブジェクトを作成してメモリを浪費する代わりに、同じ内容のすべてのインターンされた文字列は同じメモリを指します。

これにより、Pythonの「is」演算子はTrueを返します。これは、同じ内容の2つの文字列が同じ文字列オブジェクトを指しているためです。これはJavaとCでも発生します。

ただし、これはメモリの節約にのみ役立ちます。さまざまなインタープリター、コンパイラー、JITエンジンが常に実行できるとは限らないため、文字列の等価性をテストするためにこれを信頼することはできません。


12

上記の回答は言語参照を引用していないため、質問は古いものですが、私は質問に回答しています

実際、is演算子は同一性をチェックし、==演算子は等しいかどうかをチェックします。

言語リファレンスから:

タイプは、オブジェクトの動作のほぼすべての側面に影響します。オブジェクトの同一性の重要性にも何らかの影響があります。不変の型の場合、新しい値を計算する操作は、同じ型と値を持つ既存のオブジェクトへの参照を実際に返す可能性がありますが、可変オブジェクトの場合は許可されません。たとえば、a = 1の後; b = 1、aおよびbは、実装に応じて、値が1の同じオブジェクトを参照する場合としない場合がありますが、c = []の後を参照します。d = []、cおよびdは、新しく作成された2つの異なる空のリストを参照することが保証されています。(c = d = []は、cとdの両方に同じオブジェクトを割り当てることに注意してください。)

上記のステートメントから、不変の型である文字列は、「is」でチェックすると失敗する可能性があり、「is」でチェックすると成功する可能性があると推測できます。

同じことが、不変型でもあるint、tupleにも当てはまります。


8

==オペレータテスト値同値。isオペレータは、オブジェクトIDをテストし、Pythonは2が実際に(メモリ内の同じアドレスにすなわち、ライブ)同じオブジェクトであるかどうかをテストします。

>>> a = 'banana'
>>> b = 'banana'
>>> a is b 
True

この例では、Pythonは1つの文字列オブジェクトのみを作成し、両方aを作成bして参照します。その理由は、Pythonが一部の文字列を内部的にキャッシュして最適化として再利用するためです。実際には、メモリ内に文字列「バナナ」があり、aとbによって共有されます。通常の動作をトリガーするには、より長い文字列を使用する必要があります。

>>> a = 'a longer banana'
>>> b = 'a longer banana'
>>> a == b, a is b
(True, False)

2つのリストを作成すると、2つのオブジェクトが取得されます。

>>> a = [1, 2, 3]
>>> b = [1, 2, 3]
>>> a is b
False

この場合、2つのリストは同じ要素であるが、同じオブジェクトではないため同一ではないため、同等であると言えます。2つのオブジェクトが同一の場合、それらも同等ですが、同等の場合、必ずしも同一であるとは限りません。

aオブジェクトをb = a参照し、を割り当てた場合、両方の変数が同じオブジェクトを参照します。

>>> a = [1, 2, 3]
>>> b = a
>>> b is a
True

7

isメモリの場所を比較します。オブジェクトレベルの比較に使用されます。

==プログラム内の変数を比較します。値レベルでのチェックに使用されます。

is アドレスレベルの等価性をチェックします

== 値レベルの同等性をチェックします


3

is同一性テスト、==同等性テストです(Pythonドキュメントを参照))。

ほとんどの場合、if a is b、then a == b。ただし、次のような例外があります。

>>> nan = float('nan')
>>> nan is nan
True
>>> nan == nan
False

したがって、使用できるのisは同一性テストのみで、等価性テストは使用できません。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.