「==」と「is」に違いはありますか?


630

私のGoogle-fuは失敗しました。

Pythonでは、等価性の次の2つのテストは同等ですか?

n = 5
# Test one.
if n == 5:
    print 'Yay!'

# Test two.
if n is 5:
    print 'Yay!'

これは、インスタンスを比較するオブジェクト(listたとえば)にも当てはまりますか?

わかりましたので、これは私の質問に答えます:

L = []
L.append(1)
if L == [1]:
    print 'Yay!'
# Holds true, but...

if L is [1]:
    print 'Yay!'
# Doesn't.

では、==値がis同じオブジェクトであるかどうかを確認するために、値をテストしますか?

回答:


928

isTrue2つの変数が同じオブジェクトを指している==場合、変数によって参照されるオブジェクトが等しい場合に返されます。

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

# Make a new copy of list `a` via the slice operator, 
# and assign it to variable `b`
>>> b = a[:] 
>>> b is a
False
>>> b == a
True

あなたのケースでは、Pythonは実装の詳細である小さな整数オブジェクトをキャッシュするため、2番目のテストのみが機能します。これより大きい整数の場合、これは機能しません。

>>> 1000 is 10**3
False
>>> 1000 == 10**3
True

同じことが文字列リテラルにも当てはまります。

>>> "a" is "a"
True
>>> "aa" is "a" * 2
True
>>> x = "a"
>>> "aa" is x * 2
False
>>> "aa" is intern(x*2)
True

こちらの質問もご覧ください。


2
私はそれを見つけました:echo 'import sys;tt=sys.argv[1];print(tt is "foo", tt == "foo", id(tt)==id("foo"))'| python3 - foo出力:False True False
ahuigo 2018

b = a[:]スライスオペレーターリストのコピー部分で失くしたので、コメントを追加してコメントを追加しました。適用する前に編集内容をレビューする必要がないというしきい値に達したようです。うまくいけば、それでクールです。とにかく、ここに私が出会ったリストをコピーする方法についての便利なリファレンスがあります、そしてあなたが何をしているかを理解するために参照しなければなりませんでした:stackoverflow.com/a/2612815/4561887
Gabriel Staples

違いを示すもう1つの方法は、異なるタイプのオブジェクトを比較することです。もちろん、同じオブジェクトになることはありませんが、を使用する場合は等しいと見なされ==ます。だから5.0、例えば、一方では、浮動小数点値である5整数です。ただし、同じ値を表すため、5.0 == 5引き続き戻りTrueます。パフォーマンスとダックタイピングに関してisは、オペランドのメモリアドレスを比較することにより、常にインタプリタによってテストされますが、==それ自体が他のものと等しいと定義するかどうかを決定するのはオブジェクト次第です。
Bachsau

3
1000 is 10**3Python 3.7では10 ** 3がtypeであるため、Trueと評価されますint。ただし1000 is 1e3、1e3がtypeであるため、Falseと評価されfloatます。
Ahmed Fasih

@AhmedFasih trueであるかどうか1000 is 10**3は実装に依存し、コンパイラが式を事前に評価することに依存します10**3x=10; 1000 is x**3はに評価されFalseます。
chepner

313

==またはをいつ使用するかを示す簡単な経験則がありますis

  • ==価値の平等のためです。2つのオブジェクトの値が同じかどうかを知りたい場合に使用します。
  • is参照の等価性のためです。2つの参照が同じオブジェクトを参照しているかどうかを知りたい場合に使用します。

一般に、何かを単純な型と比較する場合、通常は値が等しいかどうかをチェックしているので、を使用する必要があります==。たとえば、この例の意図は、xが2 と同じオブジェクトを参照している==かどうかでxはなく、xが2()に等しい値を持っているかどうかを確認することです。


その他の注意点:CPython参照実装の動作方法のため、is整数の参照の等価性を誤って比較すると、予期しない一貫性のない結果が得られます。

>>> a = 500
>>> b = 500
>>> a == b
True
>>> a is b
False

それは私たちが期待abていたこととほぼ同じです。そして、同じ値を持っていますが、別個のエンティティです。しかし、これはどうですか?

>>> c = 200
>>> d = 200
>>> c == d
True
>>> c is d
True

これは以前の結果と一致していません。何が起きてる?Pythonのリファレンス実装は、パフォーマンス上の理由から、-5..256の範囲の整数オブジェクトをシングルトンインスタンスとしてキャッシュすることがわかりました。これを示す例は次のとおりです。

>>> for i in range(250, 260): a = i; print "%i: %s" % (i, a is int(str(i)));
... 
250: True
251: True
252: True
253: True
254: True
255: True
256: True
257: False
258: False
259: False

これは、使用しないもう1つの明らかな理由isです。値を等しくするために誤って使用している場合の動作は、実装に任されています。


a=500and の最初の例に関しては、[-5、256]の間の整数にb=500設定するaba is b実際にはを返すことを指摘したかっただけTrueです。詳細はこちら:stackoverflow.com/q/306313/7571052
AsheKetchum

1
@AsheKetchum、はい、私が書いたことに注意してください。「Pythonのリファレンス実装は、パフォーマンス上の理由から、-5..256の範囲の整数オブジェクトをシングルトンインスタンスとしてキャッシュすることがわかりました。」
John Feminella、


32

==isPython には違いがありますか?

はい、非常に重要な違いがあります。

==:等しいかどうかを確認-セマンティクスは、同等のオブジェクト(必ずしも同じオブジェクトである必要はない)が等しいかどうかをテストすることです。などのドキュメントは言います

演算子<、>、==、> =、<=、!=は、2つのオブジェクトの値を比較します。

is:アイデンティティをチェック-セマンティクスは、オブジェクト(メモリに保持されている)オブジェクトあることです。再び、ドキュメントは言う

事業者isis notオブジェクトのアイデンティティのためのテストは:x is y場合にのみ、真であるxy同じオブジェクトです。オブジェクトIDは、id()関数を使用して決定されます。x is not y逆の真理値を生成します。

したがって、IDのチェックは、オブジェクトのIDの等価性のチェックと同じです。あれは、

a is b

と同じです:

id(a) == id(b)

ここで、idは、「同時に存在するオブジェクト間で一意であることが保証されている」(を参照help(id))整数を返す組み込み関数であり、abは任意のオブジェクトです。

その他の使用方法

セマンティクスにはこれらの比較を使用する必要があります。is身元の==確認と等価性の確認に使用します。

したがって、一般的にはis、身元の確認に使用します。これは通常、ドキュメント内で「シングルトン」と呼ばれる、メモリ内に1回だけ存在するはずのオブジェクトをチェックするときに役立ちます。

使用例is

  • None
  • enum値(enumモジュールのEnumを使用する場合)
  • 通常モジュール
  • 通常、クラス定義から生じるクラスオブジェクト
  • 通常、関数定義から生じる関数オブジェクト
  • メモリ内に1度だけ存在する必要があるその他すべて(通常、すべてのシングルトン)
  • IDによって必要な特定のオブジェクト

の通常の使用例は==次のとおりです。

  • 整数を含む数値
  • 文字列
  • リスト
  • セット
  • 辞書
  • カスタムの可変オブジェクト
  • 他の組み込み不変オブジェクト、ほとんどの場合

一般的なユースケースは、再び、について==、あなたはないかもしれませんしたいオブジェクトで同じ代わりに、それはすることができ、オブジェクトの等価 1

PEP 8の方向

PEP 8は、標準ライブラリの公式Pythonスタイルガイドでも、次の2つの使用例isについて言及しています。

のようなシングルトンとの比較Noneは、常にisまたはを 使用して行う必要がありますis not。等価演算子は使用しないでください。

また、if xあなたが本当に意味するif x is not Noneとき-例えば、デフォルトである変数または引数がNone 他の値に設定されているかどうかをテストするとき- を書くことに注意してください。他の値には、ブール値のコンテキストではfalseになる可能性のあるタイプ(コンテナーなど)がある可能性があります。

アイデンティティからの平等の推論

場合はistrueで、平等にすることができ、通常は推測される-オブジェクトは、それ自体であれば、論理的に、それは自分自身と同等にテストする必要があります。

ほとんどの場合、このロジックは真ですが、__eq__特別なメソッドの実装に依存しています。ドキュメントは言います、

等価比較(==および!=)のデフォルトの動作は、オブジェクトのIDに基づいています。したがって、同じIDを持つインスタンスの等価比較は結果として等価となり、異なるIDを持つインスタンスの等価比較は結果として不等価となります。このデフォルトの動作の動機は、すべてのオブジェクトが再帰的である必要があるということです(つまり、xはyはx == yを意味します)。

一貫性のために、以下を推奨します。

平等比較は再帰的であるべきです。言い換えれば、同一のオブジェクトは同等に比較する必要があります。

x is y 意味する x == y

これがカスタムオブジェクトのデフォルトの動作であることがわかります。

>>> class Object(object): pass
>>> obj = Object()
>>> obj2 = Object()
>>> obj == obj, obj is obj
(True, True)
>>> obj == obj2, obj is obj2
(False, False)

対比も通常は真です-何かが等しくないとテストした場合、通常はそれらが同じオブジェクトではないと推測できます。

等価性のテストはカスタマイズできるため、この推論は必ずしもすべてのタイプに当てはまるわけではありません。

例外

注目すべき例外はnan-それは常にそれ自身と等しくないとしてテストする:

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

IDのチェックは、等価性のチェック(メンバーを再帰的にチェックする必要がある場合があります)よりもはるかに高速です。

ただし、等価として複数のオブジェクトが見つかる可能性がある場合は、等価の代わりにはなりません。

リストとタプルの同等性を比較すると、オブジェクトの同一性が同等であると想定されます(これは高速チェックであるため)。これは、ロジックに一貫性がない場合に矛盾が生じる可能性がありますnan

>>> [nan] == [nan]
True
>>> (nan,) == (nan,)
True

注意書き:

問題はis、整数を比較するために使用することです。整数のインスタンスが、別の参照によって取得されたインスタンスと同じであると想定しないでください。この物語はその理由を説明しています。

コメンターには、Pythonでは、小さい整数(-5〜256を含む)がシングルトンであるという事実に基づいて、等しいかどうかをチェックする代わりに、コードがありました。

うわー、これはいくつかの陰湿なバグにつながる可能性があります。aとbは通常小さい数なので、aがbかどうかをチェックするコードがいくつかありました。バグは本番で6か月後に発生しました。これは、aとbが最終的にキャッシュされないほど十分に大きかったためです。– gwg

それは開発で働いた。ユニットテストに合格した可能性があります。

そして、それは本番環境で機能しました-コードが256より大きい整数をチェックするまで、その時点で本番環境で失敗しました。

これは、コードレビューまたはスタイルチェッカーで捕捉された可能性がある本番環境の障害です。

強調したいのはis、整数の比較には使用しないことです。


「使用しないでください」も良いルールです。慣用的にはis None例外であることが、言っている== None作品はあまりにも...
ジャン=フランソワ・ファーブル

@Jean-FrançoisFabreもう1つの例外:公式ドキュメントでは、sのis比較にを使用することが推奨されているようEnumです。
アーサー

@アーサーユースケースのリストを追加しました...
アーロンホール

19

違いは何だisとは==

==isは違う比較です!他の人がすでに言ったように:

  • == オブジェクトの値を比較します。
  • is オブジェクトの参照を比較します。

Pythonでは、名前はオブジェクトを参照します(この場合value1など)、値を格納value2するintインスタンスを参照します1000

value1 = 1000
value2 = value1

ここに画像の説明を入力してください

value2同じオブジェクトisを参照しているため、次の==ようになりますTrue

>>> value1 == value2
True
>>> value1 is value2
True

次の例では、両方が同じ整数を格納していても、名前value1value2異なるintインスタンスを参照しています。

>>> value1 = 1000
>>> value2 = 1000

ここに画像の説明を入力してください

同じ値(整数)が格納さ==れるためTrue、「値の比較」と呼ばれることがよくあります。ただし、これらは異なるオブジェクトであるため、is戻りFalseます。

>>> value1 == value2
True
>>> value1 is value2
False

いつ使用するのですか?

一般isに、はるかに高速な比較です。そのため、CPythonは小さな整数や一部の文字列などの特定のオブジェクトをキャッシュします(または再利用する方がいいでしょう)。しかし、これは、(あり得ないとしても)警告なしにいつでも変更される可能性がある実装の詳細として扱う必要があります。

次の場合にのみ使用しisてください。

  • 2つのオブジェクトが本当に同じオブジェクトであるかどうかを確認したい(同じ「値」だけではない)1つの例は、シングルトンオブジェクトを定数として使用する場合です
  • 値をPython 定数と比較したい。Pythonの定数は次のとおりです。

    • None
    • True1
    • False1
    • NotImplemented
    • Ellipsis
    • __debug__
    • クラス(int is intまたはなどint is float
    • 組み込みモジュールまたはサードパーティモジュールに追加の定数がある可能性があります。たとえばnp.ma.maskedNumPyモジュールから)

では、他のすべての場合、あなたは使うべき==等価性をチェックします。

動作をカスタマイズできますか?

==他の回答ではまだ触れられていないいくつかの側面があります。これはPythonの「データモデル」の一部です。つまり、__eq__メソッドを使用してその動作をカスタマイズできます。例えば:

class MyClass(object):
    def __init__(self, val):
        self._value = val

    def __eq__(self, other):
        print('__eq__ method called')
        try:
            return self._value == other._value
        except AttributeError:
            raise TypeError('Cannot compare {0} to objects of type {1}'
                            .format(type(self), type(other)))

これは、メソッドが実際に呼び出されていることを示すための人工的な例にすぎません。

>>> MyClass(10) == MyClass(10)
__eq__ method called
True

デフォルトでは(__eq__クラスまたはスーパークラスで他にの実装が見つからない場合)__eq__は以下を使用することに注意してくださいis

class AClass(object):
    def __init__(self, value):
        self._value = value

>>> a = AClass(10)
>>> b = AClass(10)
>>> a == b
False
>>> a == a

したがって__eq__、カスタムクラスの参照比較だけではなく、「もっと」欲しい場合は、実装することが実際に重要です。

一方、isチェックをカスタマイズすることはできません。それは、常に比較されますちょうどあなたが同じ参照を持っている場合。

これらの比較は常にブール値を返しますか?

__eq__再実装またはオーバーライドできるため、return Trueまたはに限定されませんFalse。何でも返すことができます(ただし、ほとんどの場合はブール値を返します)。

たとえば、NumPy配列で==は、配列が返されます。

>>> import numpy as np
>>> np.arange(10) == 2
array([False, False,  True, False, False, False, False, False, False, False], dtype=bool)

しかし、isチェックが常に返されますTrueFalse


1アーロンホールがコメントで述べたように:

通常は、これらの「チェック」を条件を暗黙的にブール値に変換するコンテキスト(ステートメントなど)で使用するため、何is Trueis Falseチェックしないでください。したがって、比較暗黙のブールキャストを行う、ブールキャストを行うよりも多くの作業を行うことになります。ブール値(pythonicとは見なされません)に制限されます。ifis True

PEP8が言及するように:

ブール値をと比較しTrueたり、False使用したりしないでください==

Yes:   if greeting:
No:    if greeting == True:
Worse: if greeting is True:

2
「定数」と比較するためにあなたの主張に同意するis必要があります-ブール値を指す名前はブールコンテキストでチェックする必要があります- if __debug__:やなどif not __debug__:。あなたはやるべきではありませんif __debug__ is True:if __debug__ == True:-さらに、一定のはそのためでチェックし、単に一定の意味値ではなく、シングルトンでis、その場合は意味的に正しくありませんで。アサーションをサポートするためのソースを見つけるようにあなたに挑戦します-私はあなたがそれを見つけるとは思いません。
アーロンホール

@AaronHall定数がシングルトンではないと思うのはなぜですか?なおのみNoneTrueFalse__debug__彼らは再割り当てすることはできませんので、あなたが、「一定の意味値」と呼ぶものです。しかし、それらはすべてシングルトンです。
MSeifert 2018年

PEP 8 -Ctrl-F を読み、「悪い」という単語を探します。-単体テストを行う場合は、self.assertTrueを
アーロンホール

@AaronHall状況によっては、is Trueまたはif Falseチェックが本当に必要です(しかし、そうです、これはかなりまれですが、実行する場合は、を使用して実行できますis)。そのため、CPythonでも使用されることがあります(たとえば、ここまたはここ
MSeifert

19

それらは完全に異なります。 isオブジェクトの同一性を==チェックし、等価性(2つのオペランドのタイプに依存する概念)をチェックします。

" is"が小さな整数(たとえば、5 == 4 + 1)で正しく動作するように見えるのは幸運な偶然にすぎません。これは、CPythonがシングルトンにすることで、範囲(-5〜256)の整数の格納を最適化するためです。この動作は完全に実装に依存しており、マイナーな変換操作のすべての方法で保持されることが保証されていません。

たとえば、Python 3.5では短い文字列もシングルトンになりますが、それらをスライスすると、この動作が中断されます。

>>> "foo" + "bar" == "foobar"
True
>>> "foo" + "bar" is "foobar"
True
>>> "foo"[:] + "bar" == "foobar"
True
>>> "foo"[:] + "bar" is "foobar"
False


6

正解です。isオペレータは、2つのオブジェクトのアイデンティティを比較します。==オペレータは、2つのオブジェクトの値を比較します。

オブジェクトのIDは、一度作成されると変更されることはありません。メモリ内のオブジェクトのアドレスと考えることができます。

__cmp__メソッドまたはのような豊富な比較メソッドを定義することで、オブジェクト値の比較動作を制御できます__eq__



3

簡単に言えば、is2つの参照が同じオブジェクトを指しているかどうかをチェックします。==2つのオブジェクトの値が同じかどうかを確認します。

a=[1,2,3]
b=a        #a and b point to the same object
c=list(a)  #c points to different object 

if a==b:
    print('#')   #output:#
if a is b:
    print('##')  #output:## 
if a==c:
    print('###') #output:## 
if a is c:
    print('####') #no output as c and a point to different object 

2

John Feminellaが言ったように、目的は値を比較することなので、ほとんどの場合==と!=を使用します。残りの時間に何をするかを分類したいと思います。

NoneTypeのインスタンスは1つしかありません。つまり、Noneはシングルトンです。その結果foo == Nonefoo is None同じことを意味します。ただし、isテストはより高速で、Pythonicの慣習はを使用することfoo is Noneです。

ガベージコレクションをイントロスペクションしたり、いじったりしている場合や、独自に作成した文字列インターンガジェットが機能しているかどうかなどを確認している場合は、おそらくのユースケースがfooありbarます。

TrueとFalseも(今のところ)シングルトンですがfoo == True、のユースケースやユースケースはありませんfoo is True


2

彼らのほとんどはすでにその点について答えました。(私の理解と実験に基づくが、文書化されたソースからではない)追加のメモと同様に、ステートメント

==変数によって参照されるオブジェクトが等しい場合

上記からの答えは

==変数によって参照されるオブジェクトが等しく、オブジェクトが同じタイプ/クラスに属している場合

。私は以下のテストに基づいてこの結論に達しました:

list1 = [1,2,3,4]
tuple1 = (1,2,3,4)

print(list1)
print(tuple1)
print(id(list1))
print(id(tuple1))

print(list1 == tuple1)
print(list1 is tuple1)

ここでは、リストとタプルの内容は同じですが、タイプ/クラスが異なります。


2

isとequals(==)のPythonの違い

is演算子は等価演算子と同じように見えますが、同じではありません。

isは、両方の変数が同じオブジェクトを指しているかどうかをチェックし、==記号は、2つの変数の値が同じかどうかをチェックします。

したがって、is演算子がTrueを返す場合、等式は確実にTrueになりますが、その逆はTrueになる場合とそうでない場合があります。

以下は、類似点と相違点を示す例です。

>>> a = b = [1,2,3]
>>> c = [1,2,3]
>>> a == b
True
>>> a == c
True
>>> a is b
True
>>> a is c
False
>>> a = [1,2,3]
>>> b = [1,2]
>>> a == b
False
>>> a is b
False
>>> del a[2]
>>> a == b
True
>>> a is b
False
Tip: Avoid using is operator for immutable types such as strings and numbers, the result is unpredictable.

1
別のソースから引用したテキストにはブロック引用のみを使用してください。その時点で、帰属を含める必要があります(stackoverflow.com/help/referencingを参照)。これが独自のテキストである場合は、ブロック引用符を削除してください。
Martijn Pieters

0

この投稿の他の人が質問に詳細に答えているので、主に、異なる結果をもたらす可能性のある文字列との比較を強調し、プログラマにそれらを注意深く使用することをお勧めします。is==

文字列比較の場合は、次の==代わりに使用してisください:

str = 'hello'
if (str is 'hello'):
    print ('str is hello')
if (str == 'hello'):
    print ('str == hello')

アウト:

str is hello
str == hello

ただし、以下の例==isは、異なる結果が得られます。

str = 'hello sam'
    if (str is 'hello sam'):
        print ('str is hello sam')
    if (str == 'hello sam'):
        print ('str == hello sam')

アウト:

str == hello sam

結論:

is文字列を比較するために注意深く使用する


スペースがある文字列に対して「is」がそのように機能するのはなぜですか?
Akash Gupta

以前の回答によると:Pythonは小さな整数と文字列に対してキャッシュを実行しているようです。つまり、このコードスナップショットで「hello」文字列の出現に同じオブジェクト参照を使用しているのに対し、「hello sam」のキャッシュはそのままでは実行されていません'hello'よりも比較的大きい(つまり、 'hello sam'文字列のさまざまな参照を管理しているため、 'is'演算子が後の例でfalseを返すのはこのためです)。間違っている場合は修正してください
Rida Shamasneh
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.