比較演算子

比較演算子

Pythonの比較演算子

 2 つのオブジェクト x, y を比較して、
 
 「 x と y は等しい?」
 「 x は y より大きい?」
 「 x は y に含まれる?」
 
などを判定して、True(真)または False(偽)の2択(真偽値)で答えさせる演算子を 比較演算子 (comparison operator) とよび、主に if 文 などの条件式の中で、数値 (int や float オブジェクト) の大小判定に用いられますが、後述するように、文字列やリストなども比較することができます。
 
 Python の比較演算子 には次のような種類があります。

比較演算子 True を返す条件
== x == y x と y が等しい
!= x != y x と y が等しくない
< x < y x が y より小さい
> x > y x が y より大きい
<= x <= y x が y 以下
>= x >= y x が y 以上
in x in y x が y に含まれている
not in x not in y x が y に含まれない

等価演算子「==」と非等価演算子「!=」

 「==」を等価演算子 (equality operator) といいます。実際に「 == 」を使って戻り値を確認してみます。代入演算子の「 = 」と混同しないようにしてください。「 a = 1 」は「 a に 1 を代入する」というコードですが、「 a == 1 」は「 a が 1 に等しいときに True を返し、等しくないときは False を返す」コードです。
 
 「 1 == 1 」は「 1 が 1 に等しいときは True を返し、等しくないときは False を返す」というコードなので、True を返します。

# PYTHON_EQUALITY_OPERATOR

# In[1]

print(1 == 1)
# True

 「 1 == 2 」というコードを書くと、1 と 2 は等しくないので、False を返します。

# In[2]

print(1 == 2)
# False

 非等価演算子「 != 」は被演算子同士が等しくないときに True を返し、等しいときに False を返すので、「 == 」とは真逆の結果が返ります。

# In[3]
print(1 != 1)
# False

# In[4]
print(1 != 2)
# True

「 > 」「 < 」「 >= 」「 <= 」

 「 > 」「 < 」「 >= 」「 <= 」はそれぞれ、「大きい」「小さい」「以上」「以下」を判定する演算子です。

# PYTHON_COMPARISON_OPERATORS

# In[1]

print(10 >= 20)
# False

 10 は 20 以上ではないので、False が返っています。 

in 演算子 (“in” operator)

 「 in 」は文字列やリストのようなシーケンスに特定要素が含まれるか判定する演算子です。たとえば、Kobato という文字列の中に t が含まれるかどうか判定するコードは次のようになります。

# PYTHON_IN_OPERATOR

# In[1]

print("t" in "Kobato")
# True

 もちろん含まれているので、結果は True です。
 
 リストの場合も確認しておきましょう。

# In[2]

kobato_friends = ["真理子", "小春", "沙希"]

x = "小春" in kobato_friends
print(x)
# True

 リストの要素に "小春" があるので、True が返っています。 

not in 演算子 (“not in” operator)

 「 not in 」は文字列やリストに対象要素が含まれていないときに True を、そうでない場合に False を返す演算子です。

# PYTHON_NOT_IN_OPERATOR

# In[1]
print("t" not in "python")
# Fasle

# In[2]
print("x" not in "python")
# True

 

範囲内にあるかどうかを判定する

 Python では一度に 複数の比較演算子 を使って「 a < b < c 」のような書き方をすることができます。

# PYTHON_MULTIPLE_COMPARISON_OPERATORS

# In[1]
print(5 < 10 < 20)
# True

# In[2]
print(10 < 30 < 20)
# False

# In[3]
print(7 == 7 == 7)
# True

 こうした記法ができるのが Python の特徴で、複雑な条件分枝を扱うアルゴリズムもすっきりしたコードで表現できます。

文字列の比較

 比較演算子を使って文字列同士を比較することもできます。
 たとえば、"a" < "z" に対しては True が返ります。

# PYTHON_COMPARISON_OPERATORS_UNICODE

# In[1]

print("a" < "z")
# True

 文字列は Unicode のコードポイントによって大小関係が定められています。
 コードポイントは組み込みの ord() 関数を使って確認できます。

# In[2]

# 文字列"a"のコードポイントを取得
cp_a = ord("a")

# 文字列"z"のコードポイントを取得
cp_z = ord("z")

print("a のコードポイント: {}".format(cp_a))
print("z のコードポイント: {}".format(cp_z))
# a のコードポイント: 97
# z のコードポイント: 122

 実行結果を見ると、"a" と "z" のコードポイントは、それぞれ 97, 122 なので、"z" のほうが "a" より大きいことになります。
 
 大文字 "A" と "Z" のコードポイントを調べてみましょう。

# In[3]

# 文字列"A"のコードポイントを取得
cp_A = ord("A")

# 文字列"Z"のコードポイントを取得
cp_Z = ord("Z")

print("A のコードポイント: {}".format(cp_A))
print("Z のコードポイント: {}".format(cp_Z))
# A のコードポイント: 65
# Z のコードポイント: 90

 このように、Unicode におけるアルファベットのコードポイントは

小文字のコードポイント = 大文字のコードポイント + 32

と定められているので、小文字と大文字を比較すると、小文字のほうが大きいと判定されます。

# In[4]

print("A" < "a")
# True

 複数の文字で構成される文字列同士を比較する場合、先頭の文字から順にチェックが行われます。たとえば、"abc" と "abd" を比較する場合、先頭から 2 文字目までは同じなので、"c" と "d" のコードポイントを比較して大小関係が決まります。

# In[5]

print("abc" < "abd")
# True

 文字数の異なる文字列同士も比較できます。たとえば、"abc" と "ac" であれば、2 番目の文字同士を比べて、"ac" のほうが大きいと判定されます。

# In[6]

print("abc" < "ac")
# True

 "ab" と "abc" を比較する場合、3 番目の文字同士を比べることになりますが、"ab" には 3 番目の文字列はないので「値なし」となり、"abc" のほうが大きいと判定されます。

# In[7]

#「"abc"は"ab"より大きい」の真偽
print("ab" < "abc")
# True

リスト(タプル)の比較

 リストやタプルにおいても大小関係が定められています (とはいえルールは極めて複雑です)。どちらも適用されるルールは同じなので、リストを使って説明します。
 
 リスト同士を比較する場合、先頭要素から順にチェックされて最初の異なる要素同士で大小関係が判定されます。たとえば、["x", "y", "w"] と ["x", "y", "z"] を比較すると、最初の 2 要素は同じなので、3 番目の要素同士を比較します。"z" は "w" よりも Unicode のコードポイントが大きいので (上述の「文字列の比較」を参照)、["x", "y", "z"] のほうが大きいことになります。

# PYTHON_COMPARISON_OPERATORS_LIST

# In[1]

my_bool = ["x", "y", "w"] < ["x", "y", "z"]

print(my_bool)
# True

 リストの要素数が互いに異なっていても比較は成立します。
 たとえば、["a", "b", "c"] と ["a", "d"] を比較すると、2 番目の要素同士で比較することになるので (3 番目の要素はチェックされない)、 ["a", "d"] のほうが大きいと判定されます。

# In[2]

my_bool = ["a", "b", "c"] < ["a", "d"]

print(my_bool)
# True

 次は ["a", "b"] と ["a", "b", "c"] を比較してみましょう。
 最初の 2 要素は同じなので、3 番目の要素同士で比較することになりますが、["a", "b"] には 3 番目の要素がないので「値なし」とされて、["a", "b", "c"] のほうが大きいと判定されます。

# In[3]

my_bool = ["a", "b"] < ["a", "b", "c"]

print(my_bool)
# True

 互いに異なる型の要素をもつリストを比較する場合、比較が成立する場合としない場合があります。たとえば、["a", "b"] と ["a", "c", 0] を比較した場合、2 番目の要素同士でチェックが行われるため、3 番目の要素は判定に無関係です。このようなケースでは比較が成立します。

# In[4]

my_bool = ["a", "b"] < ["a", "c", 0]

print(my_bool)
# True

 しかし、["a", "b", "c"] と ["a", "b", 0] を比較した場合、3 番目の要素で判定が行われるので、型の違いによるエラー (TypeError) が送出されます。

# In[5]

my_bool = ["a", "b", "c"] < ["a", "b", 0]

print(my_bool)
# '<' not supported between instances of 'str' and 'int'

比較演算子を定義する特殊メソッド

 自作クラスの内部の特殊メソッドを使ってオブジェクトの大小関係を定義できます。
 たとえば、__lt__() は「 < 」、__le__() は「 ≤ 」を定義します。
 
 例として質量データを表す Mass クラスを定義してみます。コンストラクタに値と単位を渡してオブジェクトを生成しますが、単位はキログラム (kg) またはポンド (b) のいずれかを選択できるようにします。

# PYTHON_COMPARISON_OPERATORS_SPECIAL_METHODS

# In[1]

# 質量クラスを定義
class Mass:
    def __init__(self, value, unit="kg"):
        self.value = (value, unit)

        # 単位がbであればkgに換算
        if unit == "b":
            self.value_kg = 0.45359237 * value
        else:
            self.value_kg = value

    # 比較演算子「<」を定義
    def __lt__(self, other):
        return self.value_kg < other.value_kg

    # 比較演算子「<=」を定義
    def __le__(self, other):
        return self.value_kg <= other.value_kg

 インスタンス生成時にポンドを選択した場合、Mass クラスの内部でキログラム換算 (1 b = 0.45359237 kg) を行なって self.value_kg に格納します。キログラムを選択した場合は、value に渡した値をそのまま self.value_kg に格納します。比較演算子は self.value_kg 同士の大小関係によって定義されます。
 
 試しに、10 キログラムのオブジェクトを生成してみましょう。

# In[2]

# kg単位の質量オブジェクトを生成
m1 = Mass(10, "kg")

print(m1.value)
# (10, 'kg')

 次に 20 ポンドのオブジェクトを生成します。

# In[3]

# ポンド単位の質量オブジェクトを生成
m2 = Mass(20, "b")

print(m2.value)
# (20, 'b')

 10 キログラムと 20 ポンドを比較してみます。

# In[4]

# 10キログラムと20ポンドを比較
print(m1 < m2)
# False

 20 ポンドは 10 キログラムに少し足りないので、m1 < m2 は False を返します。

 特殊メソッドで定義できる比較演算子をまとめておきます。

特殊メソッド 演算子
__lt__(self, other) <
__le__(self, other) <=
__eq__(self, other) ==
__ne__(self, other) !=
__gt__(self, other) >
__ge__(self, other) >=