Hatena::Groupbugrammer

蟲!虫!蟲!

Esehara Profile Site (by Heroku) / Github / bookable.jp (My Service)
過去の記事一覧はこちら

なにかあったら「えせはら あっと Gmail」まで送って頂ければ幸いです。
株式会社マリーチでは、Pythonやdjango、また自然言語処理を使ったお仕事を探しています

 | 

2011-12-16

[] "is" is not "==" -- Pythonにおける"is"と"==" 23:49

 さて、Pythonには「is」と「==」という、二つの演算子があるのですが、今回はその話題にふれてみようと思います。というのも、『はじめてのPython』を読み直してみると、「"=="は同値のもの、"is"は同一のもの」という風に書かれていたからです。Pythonにおいて、同一と定義されるものは、それが同じインスタンスであるかどうか、ということです。もう少し言うと、「メモリ上の同じアドレスに存在する同一のオブジェクトであるか」ということです。

 Pythonにおいては、変数は単に「オブジェクトへの参照を格納しているモノ」なわけです。だから、例えば

>>> a = "a"
>>> b = "a"
>>> a is b
True

 となるわけです。「何を当たり前のことを」と思うでしょうが、次の挙動を見て同じことが言えるでしょうか?

>>> [1,2,3] is [1,2,3]
False
>>> (1,2,3) is (1,2,3)
False

 あれ、明らかに一緒なのにおかしい……といったように、文字列や数字の場合、一回そのオブジェクトを生成して、それを使いまわししているので、isで比較したとしても、「メモリ上の同じアドレスに存在する」ことになります。しかしリストやタプルなどの配列みたいなものは、いちいちインスタンスを作っているので、「同一じゃねーな」ということになります。実際に、id()という関数によって、そのオブジェクトの番号について調べることができます(要するに hoge is fuga は、id(hoge) == id(fuga) と書き直すことができます)。

 実は、PythonのPEP8でも、「Noneかどうかを調べるときは"is"を使えボケ」と書いてあります。他のブログ記事をちらっと見た限りだと、一つ限りのオブジェクト(Trueとかその辺)は、"is"を使うと正確になる、という話があります。

>>> 1 == True
True
>>> 1 is True
False

 Pythonの場合、Trueの値は1なので、「==」で比較するとTrueになります。実際にTrue + Trueすると2が返ってきたりします。なので、正確にBool値におけるTrueを取り出したいときは"is"を使います。もう少しポイントになるのは、「==」は、メタプログラミング的に「__eq__」というメソッドを呼び出します。例えば、次のようなClassを実装してみます。

>>> class NoneisTrue:
...     def __eq__(self,other):
...             return True
... 
>>> none = NoneisTrue()
>>> none == None
True

 ここでわかるのは、「==」というのは、あくまでも__eq__の実装がどのようになっているのかによるのであって、必ずしもNoneと同じ値であるかどうかを調べているわけではないわけです。そもそも、同じ値かどうかという定義自体をプログラムの中で行っているわけです。なので、実装的にも、速度的にも、isで比較していたほうが安心というわけです。

 ところで、Noneについては比較が使えるようで、下のような比較も使えたりします。

>>> None < False
True

 Noneはif文に投げればFalseとして扱われますが、Falseは、値としては0なので、

>>> False < -1
False

 というところは面白かったりします。この辺、ちょっと頭の隅においておくといいかなと思ったりしました。

参考

python - Is there any difference between "foo is None" and "foo == None"? - Stack Overflow

doloopwhiledoloopwhile2011/12/21 12:38細かい話になってしまうのですが、文字列の is と == は必ずしも同じ結果にならない場合があります。
>>> a = "a"
>>> b = "a"
>>> a is b
True
が成り立つのは、aとbが同じモジュールに定義されていて、値の"a"がキャッシュされているからですが、

値が動的に生成されていると
>>> a = "a" * 2**10
>>> b = "a" * 2**10
>>> a is b
False
となってしまいます。

AlexandraAlexandra2012/02/29 13:41Stelalr work there everyone. I'll keep on reading.

figdekfigdek2012/03/01 18:094OTvxK <a href="http://jsuyyqkoquol.com/">jsuyyqkoquol</a>

qujtjhtakuqujtjhtaku2012/03/11 14:21S8NH6k <a href="http://nqbzhrucpbng.com/">nqbzhrucpbng</a>

yyihqnhtyyihqnht2012/03/14 22:206lCxJ4 , [url=http://dhockwdxnmdb.com/]dhockwdxnmdb[/url], [link=http://kualjkvrzglh.com/]kualjkvrzglh[/link], http://zyeafneuphow.com/

 |