Pythonで複数の比較演算子を連結して記述(a < x < bなど)
Pythonでは比較演算子を使った比較を連結して記述できる。a < x and x < b
を数学のようにa < x < b
と書くことが可能。
複数の比較の連結
a < x < b
は各比較部分がand
で連結されたa < x and x < b
と等価。
比較はいくらでも連鎖することができます。例えば
x < y <= z
はx < y and y <= z
と等価になります。ただしこの場合、前者ではy
はただ一度だけ評価される点が異なります (どちらの場合でも、x < 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
と等価になります。ただし、前者では各式は多くても一度しか評価されません。 6. 式 (expression) - 比較 — Python 3.11.3 ドキュメント
a
, b
, c
, ..., y
, z
が式(変数単独の場合も含む)で op1
, op2
, ..., opN
が比較演算子(<
や>
など)である場合、以下の2つは等価となる。
a op1 b op2 c ... y opN z
a op1 b and b op2 c and ... y opN z
具体例は以下の通り。and
を使う場合の書き方も同時に示す。
x = 15
print(10 < x < 20)
# True
print(10 < x and x < 20)
# True
x = 0
print(10 < x < 20)
# False
print(10 < x and x < 20)
# False
より複雑な例。
x = 15
y = 25
print(10 < x < 20 < y < 30)
# True
print(10 < x and x < 20 and 20 < y and y < 30)
# True
x = 15
y = 40
print(10 < x < 20 < y < 30)
# False
print(10 < x and x < 20 and 20 < y and y < 30)
# False
連結した場合の違い
ドキュメントにあるように、連結して記述した場合、各式は多くても一度しか評価されない。
説明のために、引数をそのまま返す簡単な関数を定義する。関数が呼ばれたことを確認するために内部でprint()
を実行している。
def test(x):
print('function is called')
return(x)
print(test(15))
# function is called
# 15
比較を連結して記述した場合、該当の関数は一度しか呼ばれない。
print(10 < test(15) < 20)
# function is called
# True
and
を使った場合、該当の関数は二度呼ばれる。
print(10 < test(15) and test(15) < 20)
# function is called
# function is called
# True
なお、X and Y
では、X
がFalse
だとY
は評価されないため、以下のような場合は連結してもしなくても該当の関数は一度だけ呼ばれる。
print(10 < test(0) < 20)
# function is called
# False
print(10 < test(0) and test(0) < 20)
# function is called
# False
このような仕組みをショートサーキット(短絡評価)と呼ぶ。
いずれにせよ、連結して記述した場合は各式は多くても一度しか評価されないので、複雑な処理を行う関数などの結果をそのまま比較する場合は連結して記述した方が無駄がない。
活用例: 数値の範囲
比較の連結が便利なのは数値の範囲を条件とする場合。
これまでの例でも示した通り。
x = 15
if 10 < x < 20:
print('result: 10 < x < 20')
else:
print('result: x <= 10 or 20 <= x')
# result: 10 < x < 20
x = 30
if 10 < x < 20:
print('result: 10 < x < 20')
else:
print('result: x <= 10 or 20 <= x')
# result: x <= 10 or 20 <= x
活用例: 複数の変数・式がすべて等しい
もう一つ便利なのは、複数の変数・式がすべて等しいかどうかを判定する場合。
値が等価であるかを判定する比較演算子==
で連結すると、すべての値が等しい場合にのみTrue
となる。
a = 10
b = 10
c = 10
if a == b == c:
print('all equal')
else:
print('not all equal')
# all equal
ひとつでも違う値があるとFalse
。
a = 10
b = 1
c = 10
if a == b == c:
print('all equal')
else:
print('not all equal')
# not all equal
値が等価でないときにTrue
を返す比較演算子!=
を使うときは注意が必要。すべての値の組み合わせが評価されるわけではないので、等価な値の組み合わせがあっても順番によってはTrue
を返す。
a = 10
b = 1
c = 100
print(a != b != c)
# True
a = 10
b = 10
c = 1
print(a != b != c)
# False
a = 10
b = 1
c = 10
print(a != b != c)
# True
複数の値がすべて異なる(ユニークである)ことを判定するには、リストに格納してから重複を判定する方法がある。以下の記事を参照。
なお、==
, !=
は値の比較。オブジェクトの同一性を比較するにはis
, is not
を使う。
- 関連記事: Pythonの==演算子とis演算子の違い
例えば、整数int
と浮動小数点数float
を比較する場合、値が等価であれば==
はTrue
を返すが、異なるオブジェクトなのでis
はFalse
を返す。
i = 10
print(type(i))
# <class 'int'>
f = 10.0
print(type(f))
# <class 'float'>
print(i == f)
# True
print(i is f)
# False
使いすぎに注意
文法的にはいろいろな書き方ができるが、上述の、
- 数値の範囲
- 複数の値が等しいか
の判定以外で比較の連結を使うとコードが読み取りにくくなるので注意。
例えば、リストなどに要素が含まれているかを判定する演算子in
も連結できるが、おそらく多くの人にとっては分かりにくい。「各式が一度しか評価されない」という点に強いメリットのある状況でもない限り、and
を使ったほうがいいだろう。
a = 100
l = [0, 10, 100, 1000]
print(50 < a in l)
# True
print(50 < a and a in l)
# True