猫野詩梨帳

かわいいはかしこい

Python クイズ ~ is 編 ~

だいぶん前の話だけれどこんな Python クイズを作りました(Python3 を想定)。

True in [1] is TrueTrueFalse かというもの。

ちょっと考えてみてください。

ヒント

ヒントです。

>>> True in [1]
True

これは True == 1, False == 0 だからです。

答え

さて、答えは実行してみるとすぐわかります。

>>> True in [1] is True
False

True in [1]True なので全体として True だろ、と思った人も多いのではないでしょうか。ぼくはそう思いました。でも違うのです。

こうすると True になります。

>>> (True in [1]) is True
True

これで勘のいいひとはわかったかもしれません。

これはおそらくですが、Python では比較演算子がチェイニング(連鎖)するからです。

Python では以下のような記述をすることができます。

>>> x = 20
>>> 10 < x < 30
True

これにより、普通 (10 < x) && (x < 30) みたいに書くところを 10 < x < 30 と書けます。

そしてこの比較演算子の連鎖は、すべての比較演算子 (< > == >= <= != is is not in not in) で発生するようなのです。

つまり、問題の True in [1] is True は、おそらくですが (True in [1]) and ([1] is True) と評価されているのだと思われます。

[1] is True は当然 False なので全体として False になります。

>>> True in [1] is True
False
>>> (True in [1]) and ([1] is True)
False
>>> [1] is True
False

気を付けること

この挙動が問題になることは殆どないと思います。

1つだけ思いついたのは、以下のような場合です。

if x in [1, 2, 3] == True:
    print("OK!")

意図としては、もし x123 だったら OK! と出力したいというものです。

とりわけ Python 初心者などの場合、もしかしたら上記のようなコードを書いてしまうことがあるかもしれません。

しかし上記のコードでは決して OK! が出力されることはありません。理由はもちろんお分かりですね?

この問題を回避するためには、単に以下のようにします。

if x in [1, 2, 3]:
    print("OK!")

Python では == True(或いは is True)のような記述は通常あまりされないので、覚えておくとよいかもしれません。

参考

docs.python.org

比較はいくらでも連鎖することができます。例えば x < y <= z は x < y and y <= z と等価になります。

...

形式的には、 a, b, c, ..., y, z が式で op1, op2, ..., opN が比較演算子である場合、 a op1 b op2 c ... y opN z は a op1 b and b op2 c and ... y opN z と等価になります。

(上記リンク内のページより引用)