2つの変数が値に設定されているPythonプログラムがあります'public'
。var1 is var2
条件式では、失敗する比較がありますが、これに変更するとvar1 == var2
、が返されますTrue
。
ここで、Pythonインタープリターを開いて、同じ「is」比較を行うと、成功します。
>>> s1 = 'public'
>>> s2 = 'public'
>>> s2 is s1
True
ここで何が欠けていますか?
2つの変数が値に設定されているPythonプログラムがあります'public'
。var1 is var2
条件式では、失敗する比較がありますが、これに変更するとvar1 == var2
、が返されますTrue
。
ここで、Pythonインタープリターを開いて、同じ「is」比較を行うと、成功します。
>>> s1 = 'public'
>>> s2 = 'public'
>>> s2 is s1
True
ここで何が欠けていますか?
is
アイデンティティテスト、==
平等テストです。コードで何が起こるかは、次のようにインタープリターでエミュレートされます。
>>> a = 'pub'
>>> b = ''.join(['p', 'u', 'b'])
>>> a == b
True
>>> a is b
False
だから、彼らが同じではないのも不思議ではありませんよね?
言い換えればa is b
、:はid(a) == id(b)
ここでの他の答えは正しいです:同一性の比較にis
使用され、同等性の比較に使用されます。気になるのは平等であるため(2つの文字列には同じ文字が含まれている必要があります)、この場合、演算子は単に間違っており、代わりに使用する必要があります。==
is
==
インタラクティブに機能する理由is
は、(ほとんどの)文字列リテラルがデフォルトでインターンされているためです。ウィキペディアから:
インターンされた文字列は、文字列の比較を高速化します。これは、文字列キーを持つハッシュテーブルに大きく依存するアプリケーション(コンパイラや動的プログラミング言語ランタイムなど)のパフォーマンスのボトルネックになることがあります。インターンなしで、2つの異なる文字列が等しいことを確認するには、両方の文字列のすべての文字を調べる必要があります。これはいくつかの理由で遅いです。文字列の長さは本質的にO(n)です。通常、メモリのいくつかの領域からの読み取りが必要であり、時間がかかります。読み取りによってプロセッサキャッシュがいっぱいになるため、他のニーズに使用できるキャッシュが少なくなります。インターンされた文字列では、元のインターン操作の後に単純なオブジェクトIDテストで十分です。これは通常、ポインタの同等性テストとして実装されます。
したがって、同じ値を持つ2つの文字列リテラル(プログラムのソースコードに文字通り入力され、引用符で囲まれた単語)がある場合、Pythonコンパイラは自動的に文字列をインターンし、両方を同じ場所に格納します。メモリの場所。(これは常に発生するとは限らず、発生する場合のルールは非常に複雑であるため、本番コードではこの動作に依存しないでください!)
インタラクティブセッションでは、両方の文字列が実際には同じメモリ位置に格納されているため、それらは同じIDを持っているため、is
演算子は期待どおりに機能します。ただし、他の方法で文字列を作成する場合(その文字列にまったく同じ文字が含まれている場合でも)、文字列は等しい可能性がありますが、同じ文字列ではありません。つまり、異なるIDを持っているためです。メモリ内の別の場所に保存されます。
is
キーワードはオブジェクトIDのテストであり==
、は値の比較です。
を使用するis
と、オブジェクトが同じオブジェクトである場合にのみ、結果がtrueになります。ただし、==
オブジェクトの値が同じである場合は常にtrueになります。
最後に注意すべきことは、このsys.intern
関数を使用して、同じ文字列への参照を確実に取得できることです。
>>> from sys import intern
>>> a = intern('a')
>>> a2 = intern('a')
>>> a is a2
True
上で指摘したように、is
文字列の同等性を判断するためにを使用するべきではありません。しかし、これは、を使用するためのある種の奇妙な要件があるかどうかを知るのに役立つ場合がありますis
。
このintern
関数は、以前はPython 2に組み込まれていましたが、Python3のsys
モジュールに移動されたことに注意してください。
is
アイデンティティテストであり、==
平等テストです。これは、2つのものが同じものであるか、または単に同等でis
あるかを確認する方法であることを意味します。
単純な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
彼らは同じ年齢ですが、同じ人の実例ではありません。文字列は別の文字列と同等である可能性がありますが、同じオブジェクトではありません。
これは補足ですが、慣用的なPythonでは、次のようなことがよくあります。
if x is None:
# Some clauses
Nullオブジェクトのインスタンスが1つ(つまり、None)であることが保証されているため、これは安全です。
何をしているのかわからない場合は、「==」を使用してください。それについてもう少し知識がある場合は、「なし」などの既知のオブジェクトに「is」を使用できます。
そうしないと、なぜ物事が機能しないのか、なぜこれが発生するのか疑問に思うことになります。
>>> a = 1
>>> b = 1
>>> b is a
True
>>> a = 6000
>>> b = 6000
>>> b is a
False
異なるPythonバージョン/実装間で同じままであることが保証されているかどうかさえわかりません。
私のPythonでの限られた経験から、is
2つのオブジェクトを比較して、同じ値を持つ2つの異なるオブジェクトではなく、同じオブジェクトであるかどうかを確認するために使用されます。 ==
値が同一であるかどうかを判別するために使用されます。
これが良い例です:
>>> s1 = u'public'
>>> s2 = 'public'
>>> s1 is s2
False
>>> s1 == s2
True
s1
はUnicode文字列でありs2
、通常の文字列です。それらは同じタイプではありませんが、同じ値です。
'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」に割り当てなかったのと同じオブジェクトを使用しなかったため、同じオブジェクトではありません。もし私が持っていたら、それらを同じオブジェクトにしたでしょう。
これは「インターン」ストリングとして知られていると思います。Pythonはこれを行い、Javaも同様であり、最適化されたモードでコンパイルする場合はCおよびC++も同様です。
2つの同じ文字列を使用する場合、2つの文字列オブジェクトを作成してメモリを浪費する代わりに、同じ内容のすべてのインターン文字列が同じメモリを指します。
これにより、同じ内容の2つの文字列が同じ文字列オブジェクトを指しているため、Pythonの「is」演算子はTrueを返します。これは、JavaとCでも発生します。
ただし、これはメモリの節約にのみ役立ちます。さまざまなインタプリタ、コンパイラ、およびJITエンジンが常にそれを実行できるとは限らないため、文字列の同等性をテストするためにこれに依存することはできません。
実際には、is
演算子はIDをチェックし、==演算子は同等性をチェックします。
言語リファレンスから:
タイプは、オブジェクトの動作のほぼすべての側面に影響します。オブジェクトIDの重要性でさえ、ある意味で影響を受けます。不変型の場合、新しい値を計算する操作は、実際には同じ型と値を持つ既存のオブジェクトへの参照を返す可能性がありますが、可変オブジェクトの場合、これは許可されません。たとえば、a=1の後。b = 1、aとbは、実装に応じて、値が1の同じオブジェクトを参照する場合としない場合がありますが、c=[]の後です。d = []、cおよびdは、新しく作成された2つの異なる一意の空のリストを参照することが保証されています。(c = d = []はcとdの両方に同じオブジェクトを割り当てることに注意してください。)
したがって、上記のステートメントから、不変型である文字列は、「is」でチェックすると失敗し、「is」でチェックすると成功する可能性があると推測できます。
同じことが当てはまりint
、tuple
これも不変タイプです。
オペレーターは==
値の同等性をテストします。オペレーターは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
is
メモリの場所を比較します。オブジェクトレベルの比較に使用されます。
==
プログラム内の変数を比較します。値レベルでのチェックに使用されます。
is
アドレスレベルの同等性をチェックします
==
値レベルの同等性をチェックします
is
はアイデンティティテストであり、==
同等性テストです(Pythonのドキュメントを参照)。
ほとんどの場合、の場合a is b
、a == b
。ただし、例外があります。たとえば、次のとおりです。
>>> nan = float('nan')
>>> nan is nan
True
>>> nan == nan
False
したがって、同一性テストにのみ使用できis
、同等性テストには使用できません。
この質問に取り組む際に明確にしなければならない基本的な概念は、 isと==の違いを理解することです。
「is」はメモリ位置を比較します。id(a)== id(b)の場合、aはbがtrueを返し、それ以外の場合はfalseを返します。
つまり、これはメモリ位置の比較に使用されていると言えます。一方、
==は等価性テストに使用されます。つまり、結果の値のみを比較するだけです。以下に示すコードは、上記の理論の例として機能する場合があります。
文字列リテラル(変数に割り当てられていない文字列)の場合、メモリアドレスは図のようになります。したがって、id(a)== id(b)です。これを残すことは自明です。