Pythonで異なる2つの変数の値が同じかどうか判定するに当たって、”==”を使うか”is”を使うか悩みがちだったのでまとめてみました。
“==”
基本的にはこのオペレーター”==”を使用していました。
Pythonを使っている方には当然ですが、オペレーター”=”は変数代入の意味になります。
イコールかどうか、をチェックする場合には”==”を使用します。
1 2 3 4 |
>>> a = 1 >>> b = 1 >>> a == b True |
四則演算から進むと普通その流れでこのオペレーターを使うかと思います。
“is”
でも色々人のコードを見ていると、同様の場所で”is”を使用しているものをちらほら見かけます。”is”でも同じ結果が出る様です。
1 2 3 |
# aとbは同じ >>> a is b True |
どちらも同じような動きをしている為、どう違うか意識せず自分も混同し始めていました。
混ぜるな注意
今回改めて調べて分かりましたが、結論から言うと、意味する所は結構異なりますので混同注意です。
データが「同じ」の意味
Pythonの公式documentation operator
— Standard operators as functions
によると
a == b はEquality
a is b はIdentity
とあります。
Equality
これは素直に値が同値かどうか、と言う話です。
“==”はその両端の比較対象が文字であれ数値やリストであれ、ただ「値」が同じである事を意味します。
Identity
しかし、Identityと言うともう少し深そうです。
そう、簡単に終わる訳がありません。Identity探しに旅に出る人すら居るご時世です。
ただ値が同じならよしとされる訳がありません。
探していると、分かりやすい説明が前に買ったこの本「Lutz, Mark. Learning Python. O’Reilly Media」の6章にありました。
この本、海外のサイトでもマストアイテムとしてよく上がっている気がします。読みこなせていない私が言うのもなんですが、説明は分かりやすいと感じています。
翻訳の上引用「”is”オーペレーターは”==”とは違って、identityをチェックします。両方の変数が同じobjectを指し示す場合のみTrueを返します。」
変数は矢印のイメージ
そう、改めて書きますが、Pythonの変数のイメージは先エントリで書いた様に矢印のイメージです。
簡単にまとめると
“==”は左右の値が同じでさえ有ればTrueを返すけれども、”is”は比較対象の左右の変数がどちらも「同じ場所にある(同idの)データ」を指していないとTrueが返ってこない、と言う話になります。同じ場所のデータなので結果的に値は同じとなり、混同しがち。
例示
リストを別の変数に保存すると、メモリ上別データになりますので、上記の通り、”==”と”is”で別の結果が返ってきます。
1 2 3 4 5 6 7 8 |
>>> A = [0, 1, 2] >>> B = [0, 1, 2] >>> A == B True >>> A is B False |
ここで”==”と”is”が同じ物と思っているとなんで???となってしまいます。
理由は上記の通り。
うん、分かりやすい。世の中こうでなくっちゃ。
今まで見かけていた、”is”が使用されていたコードも実はidentityを確認する意図だったのかも知れません。
次に見かけた時はもっとちゃんと確認しようと思った次第。
それはそれとして、ここまで読んだ辛抱強くかつ慧眼な皆様は逆にあれ?と思った事でしょう。
最初の例はどっちもTrueだったじゃん、と。
最初のサンプル
1 2 3 4 5 6 7 8 |
>>> a = 1 >>> b = 1 >>> a == b True >>> a is b True |
おっと、確かに仰るとおり。
説明と矛盾があるじゃん!!!
でも大丈夫。
そんなあなたへの回答もこの本「Lutz, Mark. Learning Python. O’Reilly Media」の6章には書いてあります。この方、きっとPythonの神の1人ですね。
翻訳の上引用「小さなintegersやstringsの場合、一旦置いといて(cacheに保存)して、再使用されます」
と言う事で、リストなどは全く別のIdentityになるのでFalseが返りますが、”1″等の小さなintegerや同様に小さなstringの場合は同じメモリ上のデータを再利用する為、Identityが同じになってしまう訳です。
idを調べてみる
それぞれのidentityを調べてみましょう。
多分皆さんが実行するとその度毎違うidが割り当てられると思いますが、私の時はこんな感じ。
1 2 3 4 5 6 7 8 9 |
>>> id(a) 4543454992 >>> id(b) 4543454992 >>> id(A) 4547385856 >>> id(B) 4547041552 |
小さいintegerのaとbは同じidでしたが、リストのAとBは異なるidである事が分かります。
どこまでが小さいintegerなのか?
と言う事で、どこまでなら同じidを共有出来る小さいintegers(small integers)なのか、調べてみましょう。
1 2 3 4 5 6 7 |
>>> a, b = 1, 1 >>> while a is b: >>> a += 1 >>> b += 1 >>> print(a - 1 , b - 1) 256,256 |
while文でFalseが出た数字が最後のa, bなので1を引いたa, bが同idのintegerになります。式はスマートではありませんが、分かりました。
と言う事で256まで、2の8乗で1バイトで収まる文字まで、と考えてよさそうです。
確認
と言う事で念の為確認。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
>>> c = 256 >>> d = 256 >>> id(c) 4468170480 >>> id(d) 4468170480 >>> e = 257 >>> f = 257 >>> id(e) 4471904304 >>> id(f) 4471904240 |
おお、確かに256迄は同じidで257になった途端別のidになりました。
無事に想定道理の結果が出てほっと胸をなで下ろしています。
ここで疑問が出てしまった。
コンピュータのデータの持ち方は0からスタートしているはずなので、255までが1バイトじゃないのだろうか?
この辺りその内分かったらまた更新します。