web-dev-qa-db-ja.com

'=='または 'is'を使用して文字列を比較すると、異なる結果が得られることがあるのはなぜですか。

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

私が自分のPythonインタプリタを開いて同じ "is"比較をすれば成功します。

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

私はここで何が足りないのですか?

1012
jottos

isはアイデンティティテスト、==は等価テストです。あなたのコードで起こることは、このようにインタプリタでエミュレートされるでしょう:

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

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

言い換えれば、isid(a) == id(b)です。

1381
SilentGhost

ここでの他の答えは正しいです。is identity 比較に使用され、== equality 比較に使用されます。気にするのは等価であるため(2つの文字列は同じ文字を含むべきです)、この場合はis演算子は単に間違っていて、代わりに==を使用するべきです。

isが対話的に機能するのは、(ほとんどの)文字列リテラルがデフォルトで interned だからです。ウィキペディアより

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

そのため、同じ値を持つ2つの文字列リテラル(プログラムのソースコードに引用符で囲まれた文字通りに入力された単語)がある場合、Pythonコンパイラは自動的にそれらを同じ文字列に格納します。メモリ位置(これは always は起こりません、そしてこれが起こるときの規則はかなり複雑ですので、プロダクションコードではこの振る舞いに頼らないでください!)

インタラクティブセッションでは、両方の文字列は実際には同じメモリ位置に格納されているため、同じ identity を持つため、is演算子は期待どおりに機能します。しかし、他の方法で文字列を作成すると(その文字列に 正確に 同じ文字が含まれていても)、その文字列は equal になりますが、 同じではありません。 string - つまり、メモリ内の別の場所に格納されているため、異なる identity を持ちます。

507
Daniel Pryden

isキーワードはオブジェクトの同一性のテストで、==は値の比較です。

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

100
Thomas Owens

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

>>> a = intern('a')
>>> a2 = intern('a')
>>> a is a2
True

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

内部関数は、組み込み関数であることからPython 3用のモジュールsys内にあることに移動しました。

54
Jason Baker

isはアイデンティティテスト、==は等価テストです。これが意味することは、isは2つのことが 同じ それとも同等かどうかをチェックする方法であるということです。

単純な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

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

37
TankorSmash

これは補足ですが、慣用的なPythonでは、次のようなことがよくあります。

if x is None: 
    # some clauses

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

34
Gregg Lind

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

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

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

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

26
Mattias Nilsson

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

これは良い例です。

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

s1はUnicode文字列、s2は通常の文字列です。それらは同じ型ではありませんが、同じ値です。

19
Jack M.

私はそれが 'is'比較が偽に評価されるとき、2つの異なるオブジェクトが使われるという事実と関係があると思います。それがtrueと評価されれば、それは内部的に同じ正確なオブジェクトを使用し、新しいものを作成しないことを意味します。同じオブジェクトを使用します。

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

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

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

16
meder omuraliev

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

2つの文字列オブジェクトを作成してメモリを無駄にするのではなく、2つの同一の文字列を使用すると、同じ内容のすべての文字列は同じメモリを指します。

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

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

12
Zan Lynx

上記の回答は言語リファレンスを引用していないため、質問は古くても質問に答えています

実際、is演算子は同一性をチェックし、==演算子は同等性をチェックし、

言語リファレンスから:

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

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

不変タイプでもあるint、Tupleにも同じことが当てはまります

10
Ram

==演算子テスト値の等価性。 is演算子はオブジェクトの同一性をテストし、Pythonはこの2つが本当に同じオブジェクトかどうかをテストします(つまり、メモリ内の同じアドレスに存在します)。

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

この例では、Pythonは1つの文字列オブジェクトしか作成しておらず、abの両方がそれを参照しています。その理由は、Pythonはいくつかの文字列を内部的にキャッシュして最適化として再利用するためです。実際、aとbによって共有される文字列 'banana'がメモリ内に存在するだけです。通常の動作を引き起こすには、もっと長い文字列を使う必要があります。

>>> 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つのリストは同等であると言えます。 2つのオブジェクトが同一の場合、それらも同等ですが、同等の場合、それらは必ずしも同一ではありません。

aがオブジェクトを参照しているときにb = aを代入すると、両方の変数は同じオブジェクトを参照します。

>>> a = [1, 2, 3]
>>> b = a
>>> b is a
True
6
X. Wang

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

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

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

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

2
johnashu

isはアイデンティティーテスト、==は等価テストです( Python Documentation を参照)。

ほとんどの場合、a is bであればa == bです。しかし、例外があります。例えば:

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

そのため、isは同一性テストにのみ使用でき、等価テストには使用できません。

2
Ryan