Python 3.8 の概要 (その8) - Did you mean "=="?
さて、質問です。
a = 1.0 a is 1.0
上記の処理で、a is 1.0
の結果は True
となるでしょうか、それとも False
となるでしょうか?
True
と答えたあなた、不正解です。反省してください。
False
と答えたあなた、同じく不正解です。猛省してください。
正解は 「わからない」 です。
Pythonインタープリタを起動して、対話的に実行してみましょう。
>>> a = 1.0 >>> a is 1.0 False
False
ですね。a
に代入した float
オブジェクトと、a is 1.0
で比較している float
オブジェクトは、同じ値ですが異なるオブジェクトです。
でも、ちょっと書き換えて、同じ処理を関数の中で実行するとどうでしょう?
>>> def test(): ... a = 1.0 ... return a is 1.0 ... >>> test() True
True
ですね。まったく同じように書いているのに、グローバルに実行する場合と、関数内で実行する場合では、結果が異なっています
このように、定数を is
で比較しても、意味のある結果は得られません。 プログラミング初心者が、変数が同じ値かどうか調べるのに is
演算子を使ってしまうことがありますが、これは間違いです。==
を使わなくてはなりません。
>>> a = 1.0 >>> a == 1.0 True
だいぶ前に is演算子の不思議で解説しましたが、スクリプト中で 1.0
や "hello"
などの数値や文字列、タプルなどの定数を書いたとき、対応する数値オブジェクトや文字列オブジェクトを新しく作るのか、それとも作成済みのオブジェクトを使い回すのか、言語仕様では決められていません。つまり、1.0 is 1.0
という式の値はやってみなければわからないし、やってみても次にやったときに同じ結果になるとは限らないのです。
ということで、Python3.8 では、このような比較を行うと警告が表示されるようになりました。
>>> a = 1.0 >>> a is 1.0 <stdin>:1: SyntaxWarning: "is" with a literal. Did you mean "=="? False
「はい? 正気ですか? is
? ==
の間違いじゃないですか? 定数ですよこれ?」と言われてるわけです。素直に ==
を使いましょう。
is が使える場合
と書きましたが、is
での比較が推奨されている場合もあります。
https://www.python.org/dev/peps/pep-0008/#programming-recommendations では、
Comparisons to singletons like None should always be done with is or is not, never the equality operators.
(
None
などのシングルトンとの比較は、==
ではなく、常にis
かis not
で行います)
とされています。
上で書いたように、1.0
や abc
などの定数値オブジェクトは、どんなときに新しく作られ、どんなときに作成済みのオブジェクトを使い回すのか、決まっていません。
しかし、例外として、「オブジェクトが常に一つだけ存在する」と言語仕様で決められている値があり、「シングルトン」 と呼ばれます。シングルトンなオブジェクトは、Python開始時に一つだけ作成され、終了するまで削除されずにそのオブジェクトを使いまわします。
このようなシングルトンな値との比較は、同じ値のオブジェクトは一つだけしか存在しないので、==
ではなく is
を使っても安全です。
シングルトンの代表例として、None
があります。None
は NoneType
型のオブジェクトですが、NoneType
型はインスタンスを一つだけしか持たず、None is None
という式は、常に True
となることが保証されています。
ですから、シングルトンな値との比較の場合は、is
演算子で比較しても警告は出力されません。
>>> a = None >>> a is None True
シングルトンには、他にも True
と False
があります。True
と False
は bool
型のオブジェクトですが、どちらも常にひとつだけ存在する事になっています。したがって、この場合も True is True
や False is False
の結果は常に True
となることが保証されていますので、 is
で比較しても安心です。
>>> a = True >>> a is True True >>> a is bool('1000') True
bool
型のオブジェクトは True
と False
の2つのインスタンスが存在しますので、デザインパターンでいう「シングルトン」とはちょっと違う気がしますが、それはともかくPythonでは True
と False
は is
で比較する慣習になっています。
シングルトンにはもう一つ、Ellipsis
が存在します。 普通のアプリケーションだとあんまり比較することはなさそうですが、これも is
で比較できます。
>>> a = ... >>> a is ... True >>> ... is Ellipsis True >>> ...is... True
ところで、
>>> ...is...is...is...is...is...is...is...is...is... True
これ、意味は全くありませんが一見Pythonに見えなくて好きです。