はじめに
今回、1年ぶりにPythonでbool演算子を書いた。
ここ最近は、仕事でもGo言語ばかり触っていたので、and
ではなく&&
と書いてしまった。
そしたら、テキストエディタ様に怒られ、1つ消して&としたところでテキストエディタが許してくた。
『あ、こうだっけー?』なんて思いながら、動作確認してみたらbool演算してくれてそうだったら、そのままコーディングを進めてしまい、発見が遅れてしまってハマったので、残しておこうと思う。
いきなり全コード
flag_a = True
flag_b = True
# 1. 論理AND演算子での比較
if flag_a and flag_b:
print("1. True!")
else:
print("1. False...")
# 2. 誤って&で比較しようとした場合
if flag_a & flag_b:
print("2. True!")
else:
print("2. False...")
# Trueではなく謎の数値2が入っていた場合
flag_a = 2
# 3. 論理AND演算子での比較し、flag_aに謎の数値2が入っていた場合
if flag_a and flag_b:
print("3. True!")
else:
print("3. False...")
# 4. 誤って&で比較し、flag_aに謎の数値2が入っていた場合
if flag_a & flag_b:
print("4. True!")
else:
print("4. False...")
# 1. True!
# 2. True!
# 3. True!
# 4. False...
そもそも
andってなんだっけ
後で考えたら当然なんだけど、Pythonではbool演算子ではand
を使う。
flag_a = True
flag_b = True
# 1. 論理AND演算子での比較
if flag_a and flag_b:
print("1. True!")
else:
print("1. False...")
# -> 1. flag_a and flag_b is True!
プログラミングの初歩の部分なので、細かい説明は省略するけど、こんな感じで動く。
&ってなんだっけ
&
はビット論理AND演算子と呼ばれる。
一般的な挙動としてはこんな感じ。
print(10 & 12)
# -> 8
これだけ見るとワケ分からないかもしれないけど、めっちゃ要約すると&
はビット…つまり2進数にした状態で演算するものらしい。
つまり、10進数の10
を2進数にした1010
と、10進数の12
を2進数にした1100
を使って演算するということになる。
ビット論理AND演算子は、各値の対応する桁を見比べて、どちらの値も1だった場合のみ1になる。
(それ以外の場合は全て0になる)
↓こんな感じ
1010 => 10
1100 => 12
------------
1000 => 8
これによって1000
という結果が導き出され、これを10進数に直すと8になる。
bool演算のつもりで&を使うと
こんな風に、まったく違うand
と&
だけど、bool演算子と間違えて使うと、発見が遅れることがある。
挙動が似ている
本来なら↓こう書くべきところを…
flag_a = True
flag_b = True
# 1. 論理AND演算子での比較
if flag_a and flag_b:
print("1. True!")
else:
print("1. False...")
# -> 1. True!
間違えて↓こう書いてしまったら。
flag_a = True
flag_b = True
# 2. 誤って&で比較しようとした場合
if flag_a & flag_b:
print("2. True!")
else:
print("2. False...")
# -> 2. True!
出力結果は同じになる。
これは、True
を2進数で表現すると1
になるが、True
とTrue
だと当然1
と1
の演算のため、1
が導き出され、True
になるためだ。
しかし当然、挙動が変わることもある
このせいで、ちゃんとbool演算できてそうだなーなんて思ってたら、なんか挙動が違うことも…
これのせいでめっちゃハマった。
flag_a = 2 # Trueではなく謎の2という数値が入っていたら
flag_b = True
# 3. 論理AND演算子での比較し、flag_aに謎の数値2が入っていた場合
if flag_a and flag_b:
print("3. True!")
else:
print("3. False...")
# 4. 誤って&で比較し、flag_aに謎の数値2が入っていた場合
if flag_a & flag_b:
print("4. True!")
else:
print("4. False...")
# 結果
# 3. True!
# 4. False...
bool演算子とビット論理AND演算子で違う値が出る。
これは先程の説明通り、True
は2進数にすると1
になるが、10進数の2
は2進数にすると10
になる。
これをビット論理AND演算子で計算すると、↓の通りFalse
になってしまう。
01 => True
10 => 2(10進数)
------------
00 => False
そもそも、2
とTrue
をbool演算してTrue
って出すのもどうかと思うけど、Pythonはどこまでいっても動的型付け言語だし、こんなバグって残念ながら結構ある。
最後に
今回は、bool演算子のつもりで&
を使ってしまい発見が遅れたことを紹介しつつ、and
と&
の挙動の違いついて紹介しました。
一見想定通り動いてるコードって、発見が遅れますよね。
最後まで読んで頂いてありがとうございます。
参考サイト
