and/orを使って複数条件で判定したらおかしな結果になった(Python)
or
を使って条件判定したらおかしなことになった,あるある話.環境は3.7です.
あれ? そなたはNoneTypeではなかったか...
あるオブジェクトの型がlist
, tuple
, set
のいずれかであるかを判定したかったので,次のようなコードを書いた.
def check(obj): if type(obj) is list or tuple or set: # 型判定(のつもり) print('OK!') else: print('NG...')
引数のobj
にNone
が入っていたのだけれど,なんとシーケンス型だと言うではないか!
>>> check(None)
OK!
お,おう...
評価の結果は...
andやorの後に続くのは条件式であり,たとえオブジェクトであったとしてもTrue
もしくはFalse
のどちらかとして評価されてしまう.
つまり上のコードでは,type(None) is list
,tuple
,set
のいずれかがTrue
であれば,if
ブロックが実行されることになる.
True
もしくはFalse
のどちらに評価されるかはbool()
を使って調べることができる.
>>> bool(type(None) is list) False >>> bool(tuple) True >>> bool(set) True
つまり,常にif
ブロックが実行されてしまうことがわかった.
if tuple
とかで条件式が成立してしまうんだね...何気に怖い.
正しい判定コード
というわけで,書き直したコードがこちら.
def check(obj): if type(obj) is list or type(obj) is tuple or type(obj) is set: print('OK!') else: print('NG...') >>> check_sequence(None) NG... >>> check([]) OK! >>> check((1,)) OK!
まとめ:and/orのあとは条件式
はじめはわかっているつもりでも「なんかこれでいけるんじゃない?」「むしろPythonistaっぽくない??」 という謎の「Pythonならありえそう」感が出てきてしまってやらかしてしまった. 気をつけませう.